new probing algorithm

This commit is contained in:
Yves Rutschle 2018-08-13 22:29:09 +02:00
parent b6db83a701
commit 677e385fec
4 changed files with 56 additions and 36 deletions

View File

@ -1,3 +1,20 @@
vNEXT:
New probing method:
Before, probes were tried in order, repeating on the
same probe as long it returned PROBE_AGAIN before
moving to the next one. This means a probe which
requires a lot of data (i.e. returne PROBE_AGAIN for
a long time) could prevent sucessful matches from
subsequent probes. The configuration file needed to
take that into account.
Now, all probes are tried each time new data is
found. If any probe matches, use it. If at least one
probe requires more data, wait for more. If all
probes failed, connect to the last one. So the only
thing to know when writing the configuration file is
that 'anyprot' needs to be last.
v1.19: 20JAN2018
Added 'syslog_facility' configuration option to
specify where to log.

67
probe.c
View File

@ -180,13 +180,16 @@ static int is_tinc_protocol( const char *p, int len, struct proto *proto)
* */
static int is_xmpp_protocol( const char *p, int len, struct proto *proto)
{
if (memmem(p, len, "jabber", 6))
return PROBE_MATCH;
/* sometimes the word 'jabber' shows up late in the initial string,
sometimes after a newline. this makes sure we snarf the entire preamble
and detect it. (fixed for adium/pidgin) */
if (len < 50)
return PROBE_AGAIN;
return memmem(p, len, "jabber", 6) ? 1 : 0;
return PROBE_NEXT;
}
static int probe_http_method(const char *p, int len, const char *opt)
@ -372,8 +375,8 @@ static int regex_probe(const char *p, int len, struct proto *proto)
int probe_client_protocol(struct connection *cnx)
{
char buffer[BUFSIZ];
struct proto *p;
int n;
struct proto *p, *last_p;
int n, res, again = 0;
n = read(cnx->q[0].fd, buffer, sizeof(buffer));
/* It's possible that read() returns an error, e.g. if the client
@ -382,40 +385,40 @@ int probe_client_protocol(struct connection *cnx)
* function does not have to deal with a specific failure condition (the
* connection will just fail later normally). */
/* Dump hex values of the packet */
if (verbose>1) {
fprintf(stderr, "hexdump of incoming packet:\n");
hexdump(buffer, n);
}
if (n > 0) {
int res = PROBE_NEXT;
defer_write(&cnx->q[1], buffer, n);
for (p = cnx->proto; p && res == PROBE_NEXT; p = p->next) {
char* probe_str[3] = {"PROBE_NEXT",
"PROBE_MATCH",
"PROBE_AGAIN"};
if (! p->probe) continue;
if (verbose) fprintf(stderr, "probing for %s...", p->description);
cnx->proto = p;
res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p);
if (verbose) fprintf(stderr, "%s\n", probe_str[res]);
if (verbose > 1) {
fprintf(stderr, "hexdump of incoming packet:\n");
hexdump(buffer, n);
}
if (res != PROBE_NEXT)
return res;
defer_write(&cnx->q[1], buffer, n);
}
if (verbose)
fprintf(stderr,
"all probes failed, connecting to first protocol: %s\n",
protocols->description);
for (p = cnx->proto; p; p = p->next) {
char* probe_str[3] = {"PROBE_NEXT", "PROBE_MATCH", "PROBE_AGAIN"};
if (! p->probe) continue;
/* If none worked, return the first one affected (that's completely
* arbitrary) */
cnx->proto = protocols;
/* Don't probe last protocol if it is anyprot (and store last protocol) */
if (! p->next) {
last_p = p;
if (!strcmp(p->description, "anyprot"))
break;
}
res = p->probe(cnx->q[1].begin_deferred_data, cnx->q[1].deferred_data_size, p);
if (verbose) fprintf(stderr, "probing for %s: %s\n", p->description, probe_str[res]);
if (res == PROBE_MATCH) {
cnx->proto = p;
return PROBE_MATCH;
}
if (res == PROBE_AGAIN)
again++;
}
if (again)
return PROBE_AGAIN;
/* Everything failed: match the last one */
cnx->proto = last_p;
return PROBE_MATCH;
}

6
t
View File

@ -70,7 +70,7 @@ sub test_probes {
'tinc' => { data => "0 hello" },
'xmpp' => {data => "I should get a real jabber connection initialisation here" },
'adb' => { data => "CNXN....................host:..." },
'anyprot' => {data => "hello, this needs to be longer than the longest probe that returns PROBE_AGAIN" },
'anyprot' => {data => "hello anyprot this needs to be longer than xmpp and adb which expect about 50 characters, which I all have to write before the timeout!" },
);
my $cnx = new IO::Socket::INET(PeerHost => "localhost:$sslh_port");
@ -94,8 +94,8 @@ sub test_probes {
print "Received: protocol $prefix data [$data]\n";
close $cnx;
is($prefix, $p->{name});
is($data, $protocols{$p->{name}}->{data});
is($prefix, $p->{name}, "probe $p->{name} connected correctly");
is($data, $protocols{$p->{name}}->{data}, "data shoveled correctly");
}
}
}

View File

@ -6,7 +6,7 @@ foreground: true;
inetd: false;
numeric: false;
transparent: false;
timeout: 4; # Probe test writes slowly
timeout: 10; # Probe test writes slowly
pidfile: "/tmp/sslh_test.pid";
syslog_facility: "auth";