[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