mirror of
https://gitlab.labs.nic.cz/labs/bird.git
synced 2024-05-11 16:54:54 +00:00
Merge branch 'int-new-rpki-squashed' (early part) into int-new
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
#undef CONFIG_OSPF
|
||||
#undef CONFIG_PIPE
|
||||
#undef CONFIG_BABEL
|
||||
#undef CONFIG_RPKI
|
||||
|
||||
/* We use multithreading */
|
||||
#undef USE_PTHREADS
|
||||
@@ -70,4 +71,7 @@
|
||||
/* We have execinfo.h */
|
||||
#undef HAVE_EXECINFO_H
|
||||
|
||||
/* We have LibSSH */
|
||||
#undef HAVE_LIBSSH
|
||||
|
||||
#define CONFIG_PATH ?
|
||||
|
||||
382
sysdep/unix/io.c
382
sysdep/unix/io.c
@@ -1071,26 +1071,63 @@ sk_free_bufs(sock *s)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSSH
|
||||
static void
|
||||
sk_ssh_free(sock *s)
|
||||
{
|
||||
struct ssh_sock *ssh = s->ssh;
|
||||
|
||||
if (s->ssh == NULL)
|
||||
return;
|
||||
|
||||
s->ssh = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
sk_free(resource *r)
|
||||
{
|
||||
sock *s = (sock *) r;
|
||||
|
||||
sk_free_bufs(s);
|
||||
if (s->fd >= 0)
|
||||
|
||||
#ifdef HAVE_LIBSSH
|
||||
if (s->type == SK_SSH || s->type == SK_SSH_ACTIVE)
|
||||
sk_ssh_free(s);
|
||||
#endif
|
||||
|
||||
if (s->fd < 0)
|
||||
return;
|
||||
|
||||
/* FIXME: we should call sk_stop() for SKF_THREAD sockets */
|
||||
if (!(s->flags & SKF_THREAD))
|
||||
{
|
||||
close(s->fd);
|
||||
|
||||
/* FIXME: we should call sk_stop() for SKF_THREAD sockets */
|
||||
if (s->flags & SKF_THREAD)
|
||||
return;
|
||||
|
||||
if (s == current_sock)
|
||||
current_sock = sk_next(s);
|
||||
if (s == stored_sock)
|
||||
stored_sock = sk_next(s);
|
||||
rem_node(&s->n);
|
||||
}
|
||||
|
||||
if (s->type != SK_SSH && s->type != SK_SSH_ACTIVE)
|
||||
close(s->fd);
|
||||
|
||||
s->fd = -1;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1141,7 +1178,7 @@ static void
|
||||
sk_dump(resource *r)
|
||||
{
|
||||
sock *s = (sock *) r;
|
||||
static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", NULL, "IP", NULL, "MAGIC", "UNIX<", "UNIX", "DEL!" };
|
||||
static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", NULL, "IP", NULL, "MAGIC", "UNIX<", "UNIX", "SSH>", "SSH", "DEL!" };
|
||||
|
||||
debug("(%s, ud=%p, sa=%I, sp=%d, da=%I, dp=%d, tos=%d, ttl=%d, if=%s)\n",
|
||||
sk_type_names[s->type],
|
||||
@@ -1192,6 +1229,9 @@ sk_setup(sock *s)
|
||||
int y = 1;
|
||||
int fd = s->fd;
|
||||
|
||||
if (s->type == SK_SSH_ACTIVE)
|
||||
return 0;
|
||||
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
|
||||
ERR("O_NONBLOCK");
|
||||
|
||||
@@ -1304,6 +1344,14 @@ sk_tcp_connected(sock *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
|
||||
sk_passive_connected(sock *s, int type)
|
||||
{
|
||||
@@ -1356,6 +1404,201 @@ sk_passive_connected(sock *s, int type)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSSH
|
||||
/*
|
||||
* 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 automata */
|
||||
switch (s->ssh->state)
|
||||
{
|
||||
case SK_SSH_CONNECT:
|
||||
{
|
||||
switch (ssh_connect(s->ssh->session))
|
||||
{
|
||||
case SSH_AGAIN:
|
||||
/* A quick look into libSSH shows that ssh_get_fd() should return non-(-1)
|
||||
* after SSH_AGAIN is returned by ssh_connect(). This is however nowhere
|
||||
* documented but our code relies on that.
|
||||
*/
|
||||
return SSH_AGAIN;
|
||||
|
||||
case SSH_OK:
|
||||
break;
|
||||
|
||||
default:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
case SK_SSH_SERVER_KNOWN:
|
||||
{
|
||||
s->ssh->state = SK_SSH_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 SK_SSH_USERAUTH:
|
||||
{
|
||||
s->ssh->state = SK_SSH_USERAUTH;
|
||||
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 SK_SSH_CHANNEL:
|
||||
{
|
||||
s->ssh->state = SK_SSH_CHANNEL;
|
||||
s->ssh->channel = ssh_channel_new(s->ssh->session);
|
||||
if (s->ssh->channel == NULL)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
case SK_SSH_SESSION:
|
||||
{
|
||||
s->ssh->state = SK_SSH_SESSION;
|
||||
switch (ssh_channel_open_session(s->ssh->channel))
|
||||
{
|
||||
case SSH_AGAIN:
|
||||
return SSH_AGAIN;
|
||||
|
||||
case SSH_OK:
|
||||
break;
|
||||
|
||||
default:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
case SK_SSH_SUBSYSTEM:
|
||||
{
|
||||
s->ssh->state = SK_SSH_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 SK_SSH_ESTABLISHED:
|
||||
s->ssh->state = SK_SSH_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");
|
||||
|
||||
ssh_session sess = ssh_new();
|
||||
if (sess == NULL)
|
||||
ERR2("Cannot create a ssh session");
|
||||
s->ssh->session = sess;
|
||||
|
||||
const int verbosity = SSH_LOG_NOLOG;
|
||||
ssh_options_set(sess, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
ssh_options_set(sess, SSH_OPTIONS_HOST, s->host);
|
||||
ssh_options_set(sess, SSH_OPTIONS_PORT, &(s->dport));
|
||||
/* TODO: Add SSH_OPTIONS_BINDADDR */
|
||||
ssh_options_set(sess, SSH_OPTIONS_USER, s->ssh->username);
|
||||
|
||||
if (s->ssh->server_hostkey_path)
|
||||
ssh_options_set(sess, SSH_OPTIONS_KNOWNHOSTS, s->ssh->server_hostkey_path);
|
||||
|
||||
if (s->ssh->client_privkey_path)
|
||||
ssh_options_set(sess, SSH_OPTIONS_IDENTITY, s->ssh->client_privkey_path);
|
||||
|
||||
ssh_set_blocking(sess, 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(sess));
|
||||
break;
|
||||
}
|
||||
|
||||
return ssh_get_fd(sess);
|
||||
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* sk_open - open a socket
|
||||
* @s: socket
|
||||
@@ -1421,6 +1664,13 @@ sk_open(sock *s)
|
||||
do_bind = bind_port || ipa_nonzero(bind_addr);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_LIBSSH
|
||||
case SK_SSH_ACTIVE:
|
||||
s->ttx = ""; /* Force s->ttx != s->tpos */
|
||||
fd = sk_open_ssh(s);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SK_UDP:
|
||||
fd = socket(af, SOCK_DGRAM, IPPROTO_UDP);
|
||||
bind_port = s->sport;
|
||||
@@ -1501,6 +1751,7 @@ sk_open(sock *s)
|
||||
ERR2("listen");
|
||||
break;
|
||||
|
||||
case SK_SSH_ACTIVE:
|
||||
case SK_MAGIC:
|
||||
break;
|
||||
|
||||
@@ -1510,6 +1761,7 @@ sk_open(sock *s)
|
||||
|
||||
if (!(s->flags & SKF_THREAD))
|
||||
sk_insert(s);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@@ -1692,6 +1944,28 @@ sk_maybe_write(sock *s)
|
||||
reset_tx_buffer(s);
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_LIBSSH
|
||||
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;
|
||||
#endif
|
||||
|
||||
case SK_UDP:
|
||||
case SK_IP:
|
||||
{
|
||||
@@ -1716,6 +1990,7 @@ sk_maybe_write(sock *s)
|
||||
reset_tx_buffer(s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
bug("sk_maybe_write: unknown socket type %d", s->type);
|
||||
}
|
||||
@@ -1795,6 +2070,64 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSSH
|
||||
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 */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* sk_read() and sk_write() are called from BFD's event loop */
|
||||
|
||||
int
|
||||
@@ -1828,17 +2161,17 @@ sk_read(sock *s, int revents)
|
||||
else
|
||||
{
|
||||
s->rpos += c;
|
||||
if (s->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;
|
||||
}
|
||||
call_rx_hook(s, s->rpos - s->rbuf);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSSH
|
||||
case SK_SSH:
|
||||
return sk_read_ssh(s);
|
||||
#endif
|
||||
|
||||
case SK_MAGIC:
|
||||
return s->rx_hook(s, 0);
|
||||
|
||||
@@ -1877,6 +2210,27 @@ sk_write(sock *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSSH
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
if (s->ttx != s->tpos && sk_maybe_write(s) > 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user