Allow probes to say they cannot decide yet

This commit is contained in:
Ondřej Kuzník 2013-09-23 23:30:34 +01:00 committed by Yves Rutschle
parent c84a6af847
commit dbafd6510d
6 changed files with 46 additions and 34 deletions

View File

@ -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)

View File

@ -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);

18
probe.c
View File

@ -238,7 +238,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;
@ -251,16 +251,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)
@ -270,7 +273,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 */

View File

@ -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);

View File

@ -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;
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 */
prot = probe_client_protocol(&cnx);
} else {
/* Timed out: it's necessarily SSH */
prot = timeout_protocol();
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;

View File

@ -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);
}