mirror of
https://github.com/yrutschle/sslh.git
synced 2025-04-18 17:57:39 +03:00
new probing algorithm
This commit is contained in:
parent
b6db83a701
commit
677e385fec
17
ChangeLog
17
ChangeLog
@ -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
|
v1.19: 20JAN2018
|
||||||
Added 'syslog_facility' configuration option to
|
Added 'syslog_facility' configuration option to
|
||||||
specify where to log.
|
specify where to log.
|
||||||
|
67
probe.c
67
probe.c
@ -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)
|
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 the word 'jabber' shows up late in the initial string,
|
||||||
sometimes after a newline. this makes sure we snarf the entire preamble
|
sometimes after a newline. this makes sure we snarf the entire preamble
|
||||||
and detect it. (fixed for adium/pidgin) */
|
and detect it. (fixed for adium/pidgin) */
|
||||||
if (len < 50)
|
if (len < 50)
|
||||||
return PROBE_AGAIN;
|
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)
|
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)
|
int probe_client_protocol(struct connection *cnx)
|
||||||
{
|
{
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
struct proto *p;
|
struct proto *p, *last_p;
|
||||||
int n;
|
int 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
|
||||||
@ -382,40 +385,40 @@ int probe_client_protocol(struct connection *cnx)
|
|||||||
* function does not have to deal with a specific failure condition (the
|
* function does not have to deal with a specific failure condition (the
|
||||||
* connection will just fail later normally). */
|
* 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) {
|
if (n > 0) {
|
||||||
int res = PROBE_NEXT;
|
if (verbose > 1) {
|
||||||
|
fprintf(stderr, "hexdump of incoming packet:\n");
|
||||||
defer_write(&cnx->q[1], buffer, n);
|
hexdump(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 (res != PROBE_NEXT)
|
defer_write(&cnx->q[1], buffer, n);
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
for (p = cnx->proto; p; p = p->next) {
|
||||||
fprintf(stderr,
|
char* probe_str[3] = {"PROBE_NEXT", "PROBE_MATCH", "PROBE_AGAIN"};
|
||||||
"all probes failed, connecting to first protocol: %s\n",
|
if (! p->probe) continue;
|
||||||
protocols->description);
|
|
||||||
|
|
||||||
/* If none worked, return the first one affected (that's completely
|
/* Don't probe last protocol if it is anyprot (and store last protocol) */
|
||||||
* arbitrary) */
|
if (! p->next) {
|
||||||
cnx->proto = protocols;
|
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;
|
return PROBE_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
t
6
t
@ -70,7 +70,7 @@ sub test_probes {
|
|||||||
'tinc' => { data => "0 hello" },
|
'tinc' => { data => "0 hello" },
|
||||||
'xmpp' => {data => "I should get a real jabber connection initialisation here" },
|
'xmpp' => {data => "I should get a real jabber connection initialisation here" },
|
||||||
'adb' => { data => "CNXN....................host:..." },
|
'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");
|
my $cnx = new IO::Socket::INET(PeerHost => "localhost:$sslh_port");
|
||||||
@ -94,8 +94,8 @@ sub test_probes {
|
|||||||
print "Received: protocol $prefix data [$data]\n";
|
print "Received: protocol $prefix data [$data]\n";
|
||||||
close $cnx;
|
close $cnx;
|
||||||
|
|
||||||
is($prefix, $p->{name});
|
is($prefix, $p->{name}, "probe $p->{name} connected correctly");
|
||||||
is($data, $protocols{$p->{name}}->{data});
|
is($data, $protocols{$p->{name}}->{data}, "data shoveled correctly");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
test.cfg
2
test.cfg
@ -6,7 +6,7 @@ foreground: true;
|
|||||||
inetd: false;
|
inetd: false;
|
||||||
numeric: false;
|
numeric: false;
|
||||||
transparent: false;
|
transparent: false;
|
||||||
timeout: 4; # Probe test writes slowly
|
timeout: 10; # Probe test writes slowly
|
||||||
pidfile: "/tmp/sslh_test.pid";
|
pidfile: "/tmp/sslh_test.pid";
|
||||||
|
|
||||||
syslog_facility: "auth";
|
syslog_facility: "auth";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user