[sslh] [PATCH 04/10] Allow probes to say they cannot decide yet
ondra+sslh at mistotebe.net
ondra+sslh at mistotebe.net
Tue Sep 24 00:30:34 CEST 2013
From: Ondřej Kuzník <ondra at mistotebe.net>
---
common.c | 2 ++
common.h | 2 +-
probe.c | 18 +++++++++++-------
probe.h | 2 +-
sslh-fork.c | 38 +++++++++++++++++++++-----------------
sslh-select.c | 20 +++++++++++---------
6 files changed, 47 insertions(+), 35 deletions(-)
diff --git a/common.c b/common.c
index 708fc7c..c3def7c 100644
--- a/common.c
+++ b/common.c
@@ -8,6 +8,7 @@
#include <stdarg.h>
#include "common.h"
+#include "probe.h"
/* Added to make the code compilable under CYGWIN
* */
@@ -215,6 +216,7 @@ void init_cnx(struct connection *cnx)
memset(cnx, 0, sizeof(*cnx));
cnx->q[0].fd = -1;
cnx->q[1].fd = -1;
+ cnx->proto = get_first_protocol();
}
void dump_connection(struct connection *cnx)
diff --git a/common.h b/common.h
index 7d49b0f..c77e51a 100644
--- a/common.h
+++ b/common.h
@@ -69,6 +69,7 @@ struct queue {
struct connection {
enum connection_state state;
time_t probe_timeout;
+ struct proto *proto;
/* q[0]: queue for external connection (client);
* q[1]: queue for internal connection (httpd or sshd);
@@ -87,7 +88,6 @@ int connect_addr(struct addrinfo *addr, int fd_from, const char* cnx_name);
int fd2fd(struct queue *target, struct queue *from);
char* sprintaddr(char* buf, size_t size, struct addrinfo *a);
void resolve_name(struct addrinfo **out, char* fullname);
-struct proto* probe_client_protocol(struct connection *cnx);
void log_connection(struct connection *cnx);
int check_access_rights(int in_socket, const char* service);
void setup_signals(void);
diff --git a/probe.c b/probe.c
index 8866feb..0bff2be 100644
--- a/probe.c
+++ b/probe.c
@@ -237,7 +237,7 @@ static int regex_probe(const char *p, int len, struct proto *proto)
* write buffer of the connection and returns a pointer to the protocol
* structure
*/
-struct proto* probe_client_protocol(struct connection *cnx)
+int probe_client_protocol(struct connection *cnx)
{
char buffer[BUFSIZ];
struct proto *p;
@@ -250,16 +250,19 @@ struct proto* probe_client_protocol(struct connection *cnx)
* function does not have to deal with a specific failure condition (the
* connection will just fail later normally). */
if (n > 0) {
+ int res = PROBE_NEXT;
+
defer_write(&cnx->q[1], buffer, n);
- for (p = protocols; p; p = p->next) {
+ for (p = cnx->proto; p && res == PROBE_NEXT; p = p->next) {
if (! p->probe) continue;
if (verbose) fprintf(stderr, "probing for %s\n", p->description);
- if (p->probe(buffer, n, p)) {
- if (verbose) fprintf(stderr, "probe %s successful\n", p->description);
- return p;
- }
+
+ cnx->proto = p;
+ res = p->probe(cnx->q[1].defered_data, cnx->q[1].defered_data_size, p);
}
+ if (res != PROBE_NEXT)
+ return res;
}
if (verbose)
@@ -269,7 +272,8 @@ struct proto* probe_client_protocol(struct connection *cnx)
/* If none worked, return the first one affected (that's completely
* arbitrary) */
- return protocols;
+ cnx->proto = protocols;
+ return PROBE_MATCH;
}
/* Returns the structure for specified protocol or NULL if not found */
diff --git a/probe.h b/probe.h
index 55ba322..edc3aac 100644
--- a/probe.h
+++ b/probe.h
@@ -49,7 +49,7 @@ void set_protocol_list(struct proto*);
* write buffer of the connection and returns a pointer to the protocol
* structure
*/
-struct proto* probe_client_protocol(struct connection *cnx);
+int probe_client_protocol(struct connection *cnx);
/* set the protocol to connect to in case of timeout */
void set_ontimeout(const char* name);
diff --git a/sslh-fork.c b/sslh-fork.c
index c3afc84..05c0c42 100644
--- a/sslh-fork.c
+++ b/sslh-fork.c
@@ -70,39 +70,43 @@ void start_shoveler(int in_socket)
fd_set fds;
struct timeval tv;
struct addrinfo *saddr;
- int res;
+ int res = PROBE_AGAIN;
int out_socket;
struct connection cnx;
- struct proto *prot;
init_cnx(&cnx);
+ cnx.q[0].fd = in_socket;
FD_ZERO(&fds);
FD_SET(in_socket, &fds);
memset(&tv, 0, sizeof(tv));
tv.tv_sec = probing_timeout;
- res = select(in_socket + 1, &fds, NULL, NULL, &tv);
- if (res == -1)
- perror("select");
-
- cnx.q[0].fd = in_socket;
- if (FD_ISSET(in_socket, &fds)) {
- /* Received data: figure out what protocol it is */
- prot = probe_client_protocol(&cnx);
- } else {
- /* Timed out: it's necessarily SSH */
- prot = timeout_protocol();
+ while (res == PROBE_AGAIN) {
+ /* POSIX does not guarantee that tv will be updated, but the client can
+ * only postpone the inevitable for so long */
+ res = select(in_socket + 1, &fds, NULL, NULL, &tv);
+ if (res == -1)
+ perror("select");
+
+ if (FD_ISSET(in_socket, &fds)) {
+ /* Received data: figure out what protocol it is */
+ res = probe_client_protocol(&cnx);
+ } else {
+ /* Timed out: it's necessarily SSH */
+ cnx.proto = timeout_protocol();
+ break;
+ }
}
- saddr = prot->saddr;
- if (prot->service &&
- check_access_rights(in_socket, prot->service)) {
+ saddr = cnx.proto->saddr;
+ if (cnx.proto->service &&
+ check_access_rights(in_socket, cnx.proto->service)) {
exit(0);
}
/* Connect the target socket */
- out_socket = connect_addr(saddr, in_socket, prot->description);
+ out_socket = connect_addr(saddr, in_socket, cnx.proto->description);
CHECK_RES_DIE(out_socket, "connect");
cnx.q[1].fd = out_socket;
diff --git a/sslh-select.c b/sslh-select.c
index 14b3716..02f7cad 100644
--- a/sslh-select.c
+++ b/sslh-select.c
@@ -210,7 +210,6 @@ void main_loop(int listen_sockets[], int num_addr_listen)
struct timeval tv;
int max_fd, in_socket, i, j, res;
struct connection *cnx;
- struct proto *prot;
int num_cnx; /* Number of connections in *cnx */
int num_probing = 0; /* Number of connections currently probing
* We use this to know if we need to time out of
@@ -303,26 +302,29 @@ void main_loop(int listen_sockets[], int num_addr_listen)
dump_connection(&cnx[i]);
exit(1);
}
- num_probing--;
- cnx[i].state = ST_SHOVELING;
/* If timed out it's SSH, otherwise the client sent
* data so probe the protocol */
if ((cnx[i].probe_timeout < time(NULL))) {
- prot = timeout_protocol();
+ cnx[i].proto = timeout_protocol();
} else {
- prot = probe_client_protocol(&cnx[i]);
+ res = probe_client_protocol(&cnx[i]);
+ if (res == PROBE_AGAIN)
+ continue;
}
+ num_probing--;
+ cnx[i].state = ST_SHOVELING;
+
/* libwrap check if required for this protocol */
- if (prot->service &&
- check_access_rights(in_socket, prot->service)) {
+ if (cnx[i].proto->service &&
+ check_access_rights(in_socket, cnx[i].proto->service)) {
tidy_connection(&cnx[i], &fds_r, &fds_w);
res = -1;
} else {
res = connect_queue(&cnx[i],
- prot->saddr,
- prot->description,
+ cnx[i].proto->saddr,
+ cnx[i].proto->description,
&fds_r, &fds_w);
}
--
1.8.4.rc3
More information about the sslh
mailing list