mirror of
https://github.com/yrutschle/sslh.git
synced 2025-06-05 01:43:18 +03:00
refactor: separate probe reading from socket from probe on buffer, so we can call probe on buffer independantly
This commit is contained in:
parent
f077101835
commit
fccaa5fa9f
92
probe.c
92
probe.c
@ -317,17 +317,64 @@ static int regex_probe(const char *p, int len, struct sslhcfg_protocols_item* pr
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Run all the probes on a buffer
|
||||||
|
* Returns
|
||||||
|
* PROBE_AGAIN if not enough data, and set *proto to NULL
|
||||||
|
* PROBE_MATCH if protocol is identified, in which case *proto is set to
|
||||||
|
* point to the appropriate protocol
|
||||||
|
* */
|
||||||
|
int probe_buffer(char* buf, int len, struct sslhcfg_protocols_item** proto)
|
||||||
|
{
|
||||||
|
struct sslhcfg_protocols_item* p;
|
||||||
|
int i, res, again = 0;
|
||||||
|
|
||||||
|
*proto = NULL;
|
||||||
|
for (i = 0; i < cfg.protocols_len; i++) {
|
||||||
|
char* probe_str[3] = {"PROBE_NEXT", "PROBE_MATCH", "PROBE_AGAIN"};
|
||||||
|
p = &cfg.protocols[i];
|
||||||
|
|
||||||
|
if (! p->probe) continue;
|
||||||
|
|
||||||
|
if (cfg.verbose) fprintf(stderr, "probing for %s\n", p->name);
|
||||||
|
|
||||||
|
/* Don't probe last protocol if it is anyprot (and store last protocol) */
|
||||||
|
if ((i == cfg.protocols_len - 1) && (!strcmp(p->name, "anyprot")))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (p->minlength_is_present && (len < p->minlength )) {
|
||||||
|
fprintf(stderr, "input too short, %d bytes but need %d\n", len , p->minlength);
|
||||||
|
again++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = p->probe(buf, len, p);
|
||||||
|
if (cfg.verbose) fprintf(stderr, "probed for %s: %s\n", p->name, probe_str[res]);
|
||||||
|
|
||||||
|
if (res == PROBE_MATCH) {
|
||||||
|
*proto = p;
|
||||||
|
return PROBE_MATCH;
|
||||||
|
}
|
||||||
|
if (res == PROBE_AGAIN)
|
||||||
|
again++;
|
||||||
|
}
|
||||||
|
if (again)
|
||||||
|
return PROBE_AGAIN;
|
||||||
|
|
||||||
|
/* Everything failed: match the last one */
|
||||||
|
*proto = &cfg.protocols[cfg.protocols_len-1];
|
||||||
|
return PROBE_MATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
* Read the beginning of data coming from the client connection and check if
|
* Read the beginning of data coming from the client connection and check if
|
||||||
* it's a known protocol.
|
* it's a known protocol.
|
||||||
* Return PROBE_AGAIN if not enough data, or PROBE_MATCH if it succeeded in
|
* Return PROBE_AGAIN if not enough data, or PROBE_MATCH if it succeeded in
|
||||||
* which case cnx->proto is set to the appropriate protocol.
|
* which case cnx->proto is set to the appropriate protocol.
|
||||||
*/
|
*/
|
||||||
int probe_client_protocol(struct connection *cnx)
|
int probe_client_protocol(struct connection *cnx)
|
||||||
{
|
{
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
struct sslhcfg_protocols_item* p;
|
int n;
|
||||||
int i, n, res, again = 0;
|
|
||||||
|
|
||||||
n = read(cnx->q[0].fd, buffer, sizeof(buffer));
|
n = read(cnx->q[0].fd, buffer, sizeof(buffer));
|
||||||
/* It's possible that read() returns an error, e.g. if the client
|
/* It's possible that read() returns an error, e.g. if the client
|
||||||
@ -342,40 +389,15 @@ int probe_client_protocol(struct connection *cnx)
|
|||||||
hexdump(buffer, n);
|
hexdump(buffer, n);
|
||||||
}
|
}
|
||||||
defer_write(&cnx->q[1], buffer, n);
|
defer_write(&cnx->q[1], buffer, n);
|
||||||
|
return probe_buffer(cnx->q[1].begin_deferred_data,
|
||||||
|
cnx->q[1].deferred_data_size,
|
||||||
|
&cnx->proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < cfg.protocols_len; i++) {
|
/* If we read nothing, try again later */
|
||||||
char* probe_str[3] = {"PROBE_NEXT", "PROBE_MATCH", "PROBE_AGAIN"};
|
if (n == 0) return PROBE_AGAIN;
|
||||||
p = &cfg.protocols[i];
|
|
||||||
|
|
||||||
if (! p->probe) continue;
|
/* read() returned an error, so just connect to the last protocol to die */
|
||||||
|
|
||||||
if (cfg.verbose) fprintf(stderr, "probing for %s\n", p->name);
|
|
||||||
|
|
||||||
/* Don't probe last protocol if it is anyprot (and store last protocol) */
|
|
||||||
if ((i == cfg.protocols_len - 1) && (!strcmp(p->name, "anyprot")))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (p->minlength_is_present && (cnx->q[1].deferred_data_size < p->minlength )) {
|
|
||||||
fprintf(stderr, "input too short, %d bytes but need %d\n", cnx->q[1].deferred_data_size , p->minlength);
|
|
||||||
again++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p);
|
|
||||||
if (cfg.verbose) fprintf(stderr, "probed for %s: %s\n", p->name, probe_str[res]);
|
|
||||||
|
|
||||||
if (res == PROBE_MATCH) {
|
|
||||||
cnx->proto = p;
|
|
||||||
return PROBE_MATCH;
|
|
||||||
}
|
|
||||||
if (res == PROBE_AGAIN)
|
|
||||||
again++;
|
|
||||||
}
|
|
||||||
if ((again && (n > 0)) || ((n == -1) && (errno == EAGAIN)))
|
|
||||||
return PROBE_AGAIN;
|
|
||||||
|
|
||||||
/* Everything failed: match the last one */
|
|
||||||
cnx->proto = &cfg.protocols[cfg.protocols_len-1];
|
cnx->proto = &cfg.protocols[cfg.protocols_len-1];
|
||||||
return PROBE_MATCH;
|
return PROBE_MATCH;
|
||||||
}
|
}
|
||||||
|
3
probe.h
3
probe.h
@ -47,6 +47,9 @@ void set_protocol_list(struct sslhcfg_protocols_item*);
|
|||||||
*/
|
*/
|
||||||
int probe_client_protocol(struct connection *cnx);
|
int probe_client_protocol(struct connection *cnx);
|
||||||
|
|
||||||
|
/* Probe, but on a buffer */
|
||||||
|
int probe_buffer(char* buf, int len, struct sslhcfg_protocols_item** proto);
|
||||||
|
|
||||||
/* set the protocol to connect to in case of timeout */
|
/* set the protocol to connect to in case of timeout */
|
||||||
void set_ontimeout(const char* name);
|
void set_ontimeout(const char* name);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user