aboutsummaryrefslogtreecommitdiff
path: root/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'ssh')
-rw-r--r--ssh/client.c7
-rw-r--r--ssh/server.c83
2 files changed, 80 insertions, 10 deletions
diff --git a/ssh/client.c b/ssh/client.c
index 0adfffb..fc4ad96 100644
--- a/ssh/client.c
+++ b/ssh/client.c
@@ -200,6 +200,7 @@ int main(int argc, char **argv) {
printf("Connected.\n");
+retry_userauth:
switch (ssh_userauth_none(session, NULL)) {
case SSH_AUTH_ERROR:
fprintf(stderr, "Error authenticating: %s\n", ssh_get_error(session));
@@ -214,7 +215,11 @@ int main(int argc, char **argv) {
break;
case SSH_AUTH_AGAIN:
- assert(false);
+ if (ssh_get_status(session) & (SSH_CLOSED | SSH_CLOSED_ERROR)) {
+ fprintf(stderr, "Socket unexpectedly closed!\n");
+ return 1;
+ }
+ goto retry_userauth;
}
printf("Authenticated.\n");
diff --git a/ssh/server.c b/ssh/server.c
index ed578c4..cdc3dbd 100644
--- a/ssh/server.c
+++ b/ssh/server.c
@@ -12,6 +12,7 @@
#include <signal.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <arpa/inet.h>
#include <libssh/server.h>
#include <libssh/callbacks.h>
#include "util.h"
@@ -169,6 +170,16 @@ static ssh_channel chan_open_request_cb(ssh_session session, void *tdata_) {
static int backend_data_cb(int fd, int revents, void *tdata_) {
struct thread_data *tdata = (struct thread_data*)tdata_;
+ if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
+ char descr[64] = "";
+ if (revents & POLLERR) strcat(descr, "|POLLERR");
+ if (revents & POLLHUP) strcat(descr, "|POLLHUP");
+ if (revents & POLLNVAL) strcat(descr, "|POLLNVAL");
+ printf("[%d] %s on backend\n", tdata->thread_id, descr + 1);
+ close(fd);
+ tdata->should_close = true;
+ }
+
if (revents & POLLIN) {
char buffer[1024];
ssize_t nr = read(fd, buffer, sizeof buffer);
@@ -184,16 +195,55 @@ static int backend_data_cb(int fd, int revents, void *tdata_) {
return 0;
}
- if (ssh_channel_write(tdata->channel, buffer, nr) != SSH_OK) {
- printf("[%d] Error writing to ssh channel: %s\n", tdata->thread_id, ssh_get_error(tdata->channel));
- tdata->should_close = true;
- return 0;
+ int cursor = 0;
+ while (cursor < nr) {
+ int nw = ssh_channel_write(tdata->channel, buffer + cursor, nr - cursor);
+ if (nw == SSH_ERROR) {
+ printf("[%d] Error writing to ssh channel: %s\n", tdata->thread_id, ssh_get_error(tdata->channel));
+ tdata->should_close = true;
+ return 0;
+ }
+ cursor += nw;
}
}
return 0;
}
+static void print_addrinfo(FILE *stream, const struct addrinfo *info) {
+ if (info->ai_family == AF_INET) fprintf(stream, "inet ");
+ else if (info->ai_family == AF_INET6) fprintf(stream, "inet6 ");
+ else fprintf(stream, "(family=%d) ", info->ai_family);
+
+ if (info->ai_socktype == SOCK_STREAM) fprintf(stream, "stream ");
+ else if (info->ai_socktype == SOCK_DGRAM) fprintf(stream, "datagram ");
+ else fprintf(stream, "(socktype=%d) ", info->ai_socktype);
+
+ if (info->ai_protocol == IPPROTO_TCP) fprintf(stream, "TCP ");
+ else if (info->ai_protocol == IPPROTO_UDP) fprintf(stream, "UDP ");
+ else fprintf(stream, "(protocol=%d) ", info->ai_protocol);
+
+ bool success = false;
+ if (info->ai_family == AF_INET) {
+ char addrbuf[INET_ADDRSTRLEN];
+ struct sockaddr_in *sin = (struct sockaddr_in*)info->ai_addr;
+ if (inet_ntop(AF_INET, &sin->sin_addr, addrbuf, INET_ADDRSTRLEN)) {
+ fprintf(stream, "%s\n", addrbuf);
+ success = true;
+ }
+ } else if (info->ai_family == AF_INET6) {
+ char addrbuf[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 *sin = (struct sockaddr_in6*)info->ai_addr;
+ if (inet_ntop(AF_INET6, &sin->sin6_addr, addrbuf, INET6_ADDRSTRLEN)) {
+ fprintf(stream, "%s\n", addrbuf);
+ success = true;
+ }
+ }
+ if (!success) {
+ fprintf(stream, "(unknown address format: %s)\n", strerror(errno));
+ }
+}
+
// Returns whether successful.
static bool lookup_backend(const char *host, int port, struct addrinfo *dst) {
char port_string[16];
@@ -203,7 +253,7 @@ static bool lookup_backend(const char *host, int port, struct addrinfo *dst) {
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+ hints.ai_flags = AI_ADDRCONFIG;
struct addrinfo *result;
int ret = getaddrinfo(host, port_string, &hints, &result);
@@ -215,27 +265,41 @@ static bool lookup_backend(const char *host, int port, struct addrinfo *dst) {
int last_failure = 0;
bool success = false;
- for (struct addrinfo *item = result; item; item = item->ai_next) {
+ for (struct addrinfo *item = result; item; ) {
+ printf("lookup_backend: option ");
+ print_addrinfo(stdout, item);
+
int sock = socket(item->ai_family, item->ai_socktype, item->ai_protocol);
if (sock == -1) {
last_failure = errno;
+ printf(" socket() failure: %s\n", strerror(last_failure));
continue;
}
int ret = connect(sock, item->ai_addr, item->ai_addrlen);
+ last_failure = errno;
close(sock);
if (ret == 0) {
+ printf(" success!\n");
success = true;
+ // Free the rest of the linked list, keeping this item intact.
+ freeaddrinfo(item->ai_next);
*dst = *item;
dst->ai_next = NULL;
break;
} else {
- last_failure = errno;
+ printf(" connect() failure: %s\n", strerror(last_failure));
}
- }
- freeaddrinfo(result);
+ printf(" next=%p\n", item->ai_next);
+
+ // Free this element in the linked list, but preserve (and switch to) the tail.
+ struct addrinfo *next = item->ai_next;
+ item->ai_next = NULL;
+ freeaddrinfo(item);
+ item = next;
+ }
if (success) {
return true;
@@ -323,6 +387,7 @@ static void* thread_entry(void *tdata_) {
}
cleanup:
+ if (tdata->backend_fd != -1) close(tdata->backend_fd);
if (event) ssh_event_free(event);
if (tdata->channel) {
ssh_channel_close(tdata->channel);