diff options
Diffstat (limited to 'ssh')
| -rw-r--r-- | ssh/client.c | 7 | ||||
| -rw-r--r-- | ssh/server.c | 83 | 
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); | 
