mirror of
https://github.com/clearml/dropbear
synced 2025-04-23 07:34:52 +00:00
work in progress for async connect
--HG-- branch : fastopen
This commit is contained in:
parent
28f61c8b3a
commit
8795d733ec
@ -632,7 +632,7 @@ fi
|
|||||||
AC_PROG_GCC_TRADITIONAL
|
AC_PROG_GCC_TRADITIONAL
|
||||||
AC_FUNC_MEMCMP
|
AC_FUNC_MEMCMP
|
||||||
AC_FUNC_SELECT_ARGTYPES
|
AC_FUNC_SELECT_ARGTYPES
|
||||||
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
|
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev sendmsg])
|
||||||
|
|
||||||
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
|
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
|
||||||
|
|
||||||
|
299
dbutil.c
299
dbutil.c
@ -439,95 +439,6 @@ static void set_piggyback_ack(int sock) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
|
|
||||||
* return immediately if nonblocking is set. On failure, if errstring
|
|
||||||
* wasn't null, it will be a newly malloced error message */
|
|
||||||
|
|
||||||
/* TODO: maxfd */
|
|
||||||
int connect_remote(const char* remotehost, const char* remoteport, char ** errstring) {
|
|
||||||
|
|
||||||
struct addrinfo *res0 = NULL, *res = NULL, hints;
|
|
||||||
int sock;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
TRACE(("enter connect_remote"))
|
|
||||||
|
|
||||||
if (errstring != NULL) {
|
|
||||||
*errstring = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(hints));
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
|
||||||
hints.ai_family = PF_UNSPEC;
|
|
||||||
|
|
||||||
err = getaddrinfo(remotehost, remoteport, &hints, &res0);
|
|
||||||
if (err) {
|
|
||||||
if (errstring != NULL && *errstring == NULL) {
|
|
||||||
int len;
|
|
||||||
len = 100 + strlen(gai_strerror(err));
|
|
||||||
*errstring = (char*)m_malloc(len);
|
|
||||||
snprintf(*errstring, len, "Error resolving '%s' port '%s'. %s",
|
|
||||||
remotehost, remoteport, gai_strerror(err));
|
|
||||||
}
|
|
||||||
TRACE(("Error resolving: %s", gai_strerror(err)))
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sock = -1;
|
|
||||||
err = EADDRNOTAVAIL;
|
|
||||||
for (res = res0; res; res = res->ai_next) {
|
|
||||||
|
|
||||||
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
|
||||||
if (sock < 0) {
|
|
||||||
err = errno;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
setnonblocking(sock);
|
|
||||||
|
|
||||||
#if defined(__linux__) && defined(TCP_DEFER_ACCEPT)
|
|
||||||
set_piggyback_ack(sock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
|
|
||||||
if (errno == EINPROGRESS) {
|
|
||||||
TRACE(("Connect in progress"))
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
err = errno;
|
|
||||||
close(sock);
|
|
||||||
sock = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break; /* Success */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sock < 0 && !(errno == EINPROGRESS)) {
|
|
||||||
/* Failed */
|
|
||||||
if (errstring != NULL && *errstring == NULL) {
|
|
||||||
int len;
|
|
||||||
len = 20 + strlen(strerror(err));
|
|
||||||
*errstring = (char*)m_malloc(len);
|
|
||||||
snprintf(*errstring, len, "Error connecting: %s", strerror(err));
|
|
||||||
}
|
|
||||||
TRACE(("Error connecting: %s", strerror(err)))
|
|
||||||
} else {
|
|
||||||
/* Success */
|
|
||||||
set_sock_nodelay(sock);
|
|
||||||
}
|
|
||||||
|
|
||||||
freeaddrinfo(res0);
|
|
||||||
if (sock > 0 && errstring != NULL && *errstring != NULL) {
|
|
||||||
m_free(*errstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE(("leave connect_remote: sock %d\n", sock))
|
|
||||||
return sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sets up a pipe for a, returning three non-blocking file descriptors
|
/* Sets up a pipe for a, returning three non-blocking file descriptors
|
||||||
* and the pid. exec_fn is the function that will actually execute the child process,
|
* and the pid. exec_fn is the function that will actually execute the child process,
|
||||||
* it will be run after the child has fork()ed, and is passed exec_data.
|
* it will be run after the child has fork()ed, and is passed exec_data.
|
||||||
@ -1069,3 +980,213 @@ time_t monotonic_now() {
|
|||||||
return time(NULL);
|
return time(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct dropbear_progress_connection
|
||||||
|
{
|
||||||
|
struct addrinfo *res;
|
||||||
|
struct addrinfo *res_iter;
|
||||||
|
|
||||||
|
char *remotehost, *remoteport; /* For error reporting */
|
||||||
|
|
||||||
|
connect_callback cb;
|
||||||
|
void *cb_data;
|
||||||
|
|
||||||
|
struct Queue *writequeue; /* A queue of encrypted packets to send with TCP fastopen,
|
||||||
|
or NULL. */
|
||||||
|
|
||||||
|
int sock;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
|
||||||
|
Does not close sockets */
|
||||||
|
static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) {
|
||||||
|
if (c->res) {
|
||||||
|
freeaddrinfo(c->res);
|
||||||
|
}
|
||||||
|
m_free(c->remotehost);
|
||||||
|
m_free(c->remoteport);
|
||||||
|
m_free(c);
|
||||||
|
|
||||||
|
if (iter) {
|
||||||
|
list_remove(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int connect_try_next(struct dropbear_progress_connection *c) {
|
||||||
|
int err = EADDRNOTAVAIL;
|
||||||
|
struct addrinfo *r;
|
||||||
|
|
||||||
|
if (!c->res_iter) {
|
||||||
|
return DROPBEAR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (r = c->res_iter; r; r = r->ai_next)
|
||||||
|
{
|
||||||
|
assert(c->sock == -1);
|
||||||
|
|
||||||
|
c->sock = socket(c->res_iter->ai_family, c->res_iter->ai_socktype, c->res_iter->ai_protocol);
|
||||||
|
if (c->sock < 0) {
|
||||||
|
err = errno;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
setnonblocking(c->sock);
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(TCP_DEFER_ACCEPT)
|
||||||
|
set_piggyback_ack(sock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (connect(c->sock, r->ai_addr, r->ai_addrlen) < 0) {
|
||||||
|
if (errno == EINPROGRESS) {
|
||||||
|
TRACE(("Connect in progress"))
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
err = errno;
|
||||||
|
close(c->sock);
|
||||||
|
c->sock = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break; /* Success. Treated the same as EINPROGRESS */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
c->res_iter = r->ai_next;
|
||||||
|
} else {
|
||||||
|
c->res_iter = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->sock >= 0 || (errno == EINPROGRESS)) {
|
||||||
|
/* Success */
|
||||||
|
set_sock_nodelay(c->sock);
|
||||||
|
return DROPBEAR_SUCCESS;
|
||||||
|
} else {
|
||||||
|
/* XXX - returning error message through */
|
||||||
|
#if 0
|
||||||
|
/* Failed */
|
||||||
|
if (errstring != NULL && *errstring == NULL) {
|
||||||
|
int len;
|
||||||
|
len = 20 + strlen(strerror(err));
|
||||||
|
*errstring = (char*)m_malloc(len);
|
||||||
|
snprintf(*errstring, len, "Error connecting: %s", strerror(err));
|
||||||
|
}
|
||||||
|
TRACE(("Error connecting: %s", strerror(err)))
|
||||||
|
#endif
|
||||||
|
return DROPBEAR_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
|
||||||
|
* return immediately if nonblocking is set. On failure, if errstring
|
||||||
|
* wasn't null, it will be a newly malloced error message */
|
||||||
|
|
||||||
|
/* TODO: maxfd */
|
||||||
|
struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport,
|
||||||
|
connect_callback cb, void* cb_data)
|
||||||
|
{
|
||||||
|
struct dropbear_progress_connection *c = NULL;
|
||||||
|
int err;
|
||||||
|
struct addrinfo hints;
|
||||||
|
|
||||||
|
c = m_malloc(sizeof(*c));
|
||||||
|
c->remotehost = m_strdup(remotehost);
|
||||||
|
c->remoteport = m_strdup(remoteport);
|
||||||
|
c->sock = -1;
|
||||||
|
c->cb = cb;
|
||||||
|
c->cb_data = cb_data;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_family = PF_UNSPEC;
|
||||||
|
|
||||||
|
err = getaddrinfo(remotehost, remoteport, &hints, &c->res);
|
||||||
|
if (err) {
|
||||||
|
int len;
|
||||||
|
char *errstring;
|
||||||
|
len = 100 + strlen(gai_strerror(err));
|
||||||
|
errstring = (char*)m_malloc(len);
|
||||||
|
snprintf(errstring, len, "Error resolving '%s' port '%s'. %s",
|
||||||
|
remotehost, remoteport, gai_strerror(err));
|
||||||
|
c->cb(DROPBEAR_FAILURE, -1, c->cb_data, errstring);
|
||||||
|
m_free(errstring);
|
||||||
|
TRACE(("Error resolving: %s", gai_strerror(err)))
|
||||||
|
remove_connect(c, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->res_iter = c->res;
|
||||||
|
|
||||||
|
if (connect_try_next(c) == DROPBEAR_FAILURE) {
|
||||||
|
/* Should not happen - getaddrinfo() should return failure if there are no addresses */
|
||||||
|
c->cb(DROPBEAR_FAILURE, -1, c->cb_data, "No address to try");
|
||||||
|
TRACE(("leave handle_connect_fds - failed"))
|
||||||
|
remove_connect(c, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_append(&ses.conn_pending, c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_connect_fds(fd_set *writefd) {
|
||||||
|
m_list_elem *iter;
|
||||||
|
TRACE(("enter handle_connect_fds"))
|
||||||
|
for (iter = ses.conn_pending.first; iter; iter = iter->next) {
|
||||||
|
struct dropbear_progress_connection *c = iter->item;
|
||||||
|
if (c->sock >= 0) {
|
||||||
|
FD_SET(c->sock, writefd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_connect_fds(fd_set *writefd) {
|
||||||
|
m_list_elem *iter;
|
||||||
|
TRACE(("enter handle_connect_fds"))
|
||||||
|
for (iter = ses.conn_pending.first; iter; iter = iter->next) {
|
||||||
|
int val;
|
||||||
|
socklen_t vallen = sizeof(val);
|
||||||
|
struct dropbear_progress_connection *c = iter->item;
|
||||||
|
|
||||||
|
if (!FD_ISSET(c->sock, writefd)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("handling %s port %s socket %d", c->remotehost, c->remoteport, c->sock));
|
||||||
|
|
||||||
|
if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &val, &vallen) != 0) {
|
||||||
|
TRACE(("handle_connect_fds getsockopt(%d) SO_ERROR failed: %s", c->sock, strerror(errno)))
|
||||||
|
} else if (val != 0) {
|
||||||
|
/* Connect failed */
|
||||||
|
TRACE(("connect to %s port %s failed.", c->remotehost, c->remoteport))
|
||||||
|
m_close(c->sock);
|
||||||
|
c->sock = -1;
|
||||||
|
|
||||||
|
if (connect_try_next(c) == DROPBEAR_FAILURE) {
|
||||||
|
c->cb(DROPBEAR_FAILURE, -1, c->cb_data, strerror(val));
|
||||||
|
TRACE(("leave handle_connect_fds - failed"))
|
||||||
|
remove_connect(c, iter);
|
||||||
|
/* Must return here - remove_connect() invalidates iter */
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* new connection try was successfuly started, will be finished by a
|
||||||
|
later call to handle_connect_fds() */
|
||||||
|
TRACE(("leave handle_connect_fds - new try"))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* New connection has been established */
|
||||||
|
c->cb(DROPBEAR_SUCCESS, c->sock, c->cb_data, "");
|
||||||
|
remove_connect(c, iter);
|
||||||
|
TRACE(("leave handle_connect_fds - success"))
|
||||||
|
/* Must return here - remove_connect() invalidates iter */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TRACE(("leave handle_connect_fds - end iter"))
|
||||||
|
}
|
||||||
|
15
dbutil.h
15
dbutil.h
@ -76,7 +76,7 @@ void getaddrstring(struct sockaddr_storage* addr,
|
|||||||
void set_sock_nodelay(int sock);
|
void set_sock_nodelay(int sock);
|
||||||
void set_sock_priority(int sock, enum dropbear_prio prio);
|
void set_sock_priority(int sock, enum dropbear_prio prio);
|
||||||
|
|
||||||
#ifdef __linux__
|
#if defined(__linux__) && HAVE_SENDMSG
|
||||||
#define DROPBEAR_TCP_FAST_OPEN
|
#define DROPBEAR_TCP_FAST_OPEN
|
||||||
void set_listen_fast_open(int sock);
|
void set_listen_fast_open(int sock);
|
||||||
#endif
|
#endif
|
||||||
@ -89,7 +89,6 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
|
|||||||
#ifdef ENABLE_CONNECT_UNIX
|
#ifdef ENABLE_CONNECT_UNIX
|
||||||
int connect_unix(const char* addr);
|
int connect_unix(const char* addr);
|
||||||
#endif
|
#endif
|
||||||
int connect_remote(const char* remotehost, const char* remoteport, char ** errstring);
|
|
||||||
int buf_readfile(buffer* buf, const char* filename);
|
int buf_readfile(buffer* buf, const char* filename);
|
||||||
int buf_getline(buffer * line, FILE * authfile);
|
int buf_getline(buffer * line, FILE * authfile);
|
||||||
|
|
||||||
@ -118,4 +117,16 @@ time_t monotonic_now();
|
|||||||
|
|
||||||
char * expand_tilde(const char *inpath);
|
char * expand_tilde(const char *inpath);
|
||||||
|
|
||||||
|
struct dropbear_progress_connection;
|
||||||
|
|
||||||
|
/* result is DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
|
||||||
|
errstring is only set on DROPBEAR_FAILURE, returns failure message for the last attempted socket */
|
||||||
|
typedef void(*connect_callback)(int result, int sock, void* data, const char* errstring);
|
||||||
|
|
||||||
|
struct dropbear_progress_connection * connect_remote (const char* remotehost, const char* remoteport,
|
||||||
|
connect_callback cb, void *cb_data);
|
||||||
|
|
||||||
|
void set_connect_fds(fd_set *writefd);
|
||||||
|
void handle_connect_fds(fd_set *writefd);
|
||||||
|
|
||||||
#endif /* _DBUTIL_H_ */
|
#endif /* _DBUTIL_H_ */
|
||||||
|
21
packet.c
21
packet.c
@ -52,10 +52,29 @@ static buffer* buf_decompress(buffer* buf, unsigned int len);
|
|||||||
static void buf_compress(buffer * dest, buffer * src, unsigned int len);
|
static void buf_compress(buffer * dest, buffer * src, unsigned int len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct iovec * dropbear_queue_to_iovec(struct Queue *queue) {
|
||||||
|
|
||||||
|
struct iovec *iov = NULL;
|
||||||
|
struct Link *l;
|
||||||
|
int iov_max_count;
|
||||||
|
|
||||||
|
#ifndef IOV_MAX
|
||||||
|
#define IOV_MAX UIO_MAXIOV
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#error incomplete
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void dropbear_queue_consume(struct Queue *queue, ssize_t written) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* non-blocking function writing out a current encrypted packet */
|
/* non-blocking function writing out a current encrypted packet */
|
||||||
void write_packet() {
|
void write_packet() {
|
||||||
|
|
||||||
int len, written;
|
ssize_t written;
|
||||||
|
int len;
|
||||||
buffer * writebuf = NULL;
|
buffer * writebuf = NULL;
|
||||||
unsigned packet_type;
|
unsigned packet_type;
|
||||||
#ifdef HAVE_WRITEV
|
#ifdef HAVE_WRITEV
|
||||||
|
@ -145,6 +145,8 @@ struct sshsession {
|
|||||||
int signal_pipe[2]; /* stores endpoints of a self-pipe used for
|
int signal_pipe[2]; /* stores endpoints of a self-pipe used for
|
||||||
race-free signal handling */
|
race-free signal handling */
|
||||||
|
|
||||||
|
m_list conn_pending;
|
||||||
|
|
||||||
/* time of the last packet send/receive, for keepalive. Not real-world clock */
|
/* time of the last packet send/receive, for keepalive. Not real-world clock */
|
||||||
time_t last_packet_time_keepalive_sent;
|
time_t last_packet_time_keepalive_sent;
|
||||||
time_t last_packet_time_keepalive_recv;
|
time_t last_packet_time_keepalive_recv;
|
||||||
|
Loading…
Reference in New Issue
Block a user