diff --git a/ChangeLog b/ChangeLog index 413ebb4..05ccaa5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,11 @@ vNEXT: Added support for RFC4366 SNI (Travis Burtrum) + Changed configuration file format: 'probe' field is + no longer required, 'name' field can now contain + 'sni' or 'regex', with corresponding options (see + example.org) + v1.17: 09MAR2015 Support RFC5952-style IPv6 addresses, e.g. [::]:443. diff --git a/basic.cfg b/basic.cfg index 526ffbf..64942e5 100644 --- a/basic.cfg +++ b/basic.cfg @@ -19,11 +19,11 @@ listen: protocols: ( - { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; probe: "builtin"; }, - { name: "openvpn"; host: "localhost"; port: "1194"; probe: "builtin"; }, - { name: "xmpp"; host: "localhost"; port: "5222"; probe: "builtin"; }, - { name: "http"; host: "localhost"; port: "80"; probe: "builtin"; }, - { name: "ssl"; host: "localhost"; port: "443"; probe: "builtin"; }, - { name: "anyprot"; host: "localhost"; port: "443"; probe: "builtin"; } + { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; }, + { name: "openvpn"; host: "localhost"; port: "1194"; }, + { name: "xmpp"; host: "localhost"; port: "5222"; }, + { name: "http"; host: "localhost"; port: "80"; }, + { name: "ssl"; host: "localhost"; port: "443"; }, + { name: "anyprot"; host: "localhost"; port: "443"; } ); diff --git a/example.cfg b/example.cfg index f9d76fa..5ca9af6 100644 --- a/example.cfg +++ b/example.cfg @@ -23,31 +23,48 @@ listen: # List of protocols # # Each protocol entry consists of: -# name: name of the protocol +# name: name of the probe. These are listed on the command +# line (ssh -?), plus 'regex', 'sni' and 'timeout'. + # service: (optional) libwrap service name (see hosts_access(5)) -# host: host name to connect that protocol -# port: port number to connect that protocol -# probe: "builtin" or a list of regular expressions -# (can be left out, e.g. to use with on-timeout) +# host, port: where to connect when this probe succeeds +# +# Probe-specific options: +# sni: +# sni_hotnames: list of FQDN for that target +# regex: +# regex_patterns: list of patterns to match for +# that target. # # sslh will try each probe in order they are declared, and # connect to the first that matches. - +# +# You can specify several of 'regex' and 'sni'. + protocols: ( - { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; probe: "builtin"; }, - { name: "sni"; host: "localhost"; port: "993"; probe: "builtin"; sni_hostnames: [ "imap.example.org", "imap.example.com" ]; }, - { name: "openvpn"; host: "localhost"; port: "1194"; probe: [ "^\x00[\x0D-\xFF]$", "^\x00[\x0D-\xFF]\x38" ]; }, - { name: "xmpp"; host: "localhost"; port: "5222"; probe: [ "jabber" ]; }, - { name: "http"; host: "localhost"; port: "80"; probe: "builtin"; }, - { name: "ssl"; host: "localhost"; port: "443"; probe: [ "" ]; }, + { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; }, + { name: "http"; host: "localhost"; port: "80"; }, + + { name: "sni"; host: "localhost"; port: "993"; sni_hostnames: [ "mail.rutschle.net", "mail.englishintoulouse.com" ]; }, + { name: "sni"; host: "localhost"; port: "xmpp-client"; sni_hostnames: [ "im.rutschle.net", "im.englishintoulouse.com" ]; }, + +# OpenVPN + { name: "regex"; host: "localhost"; port: "1194"; regex_patterns: [ "^\x00[\x0D-\xFF]$", "^\x00[\x0D-\xFF]\x38" ]; }, +# Jabber + { name: "regex"; host: "localhost"; port: "5222"; regex_patterns: [ "jabber" ]; }, + +# Catch-all + { name: "regex"; host: "localhost"; port: "443"; regex_patterns: [ "" ]; }, + +# Where to connect in case of timeout (defaults to ssh) { name: "timeout"; service: "daytime"; host: "localhost"; port: "daytime"; } ); # Optionally, specify to which protocol to connect in case # of timeout (defaults to "ssh"). -# You can timeout to any arbitrary address by setting a -# protocol with no probe, as is the case with this example. +# You can timeout to any arbitrary address by setting an +# entry in 'protocols' named "timeout". # This enables you to set a tcpd service name for this # protocol too. on-timeout: "timeout"; diff --git a/probe.c b/probe.c index 5626983..27120c4 100644 --- a/probe.c +++ b/probe.c @@ -233,11 +233,13 @@ static int is_sni_protocol(const char *p, int len, struct proto *proto) /* Assume does not match */ valid_tls = PROBE_NEXT; - for (sni_hostname = proto->data; *sni_hostname; sni_hostname++) + for (sni_hostname = proto->data; *sni_hostname; sni_hostname++) { + fprintf(stderr, "matching [%s] with [%s]\n", hostname, *sni_hostname); if(!strcmp(hostname, *sni_hostname)) { valid_tls = PROBE_MATCH; break; } + } free(hostname); return valid_tls; @@ -365,6 +367,11 @@ T_PROBE* get_probe(const char* description) { if (!strcmp(description, "sni")) return is_sni_protocol; + /* Special case of "timeout" is allowed as a probe name in the + * configuration file even though it's not really a probe */ + if (!strcmp(description, "timeout")) + return is_true; + return NULL; } diff --git a/sslh-main.c b/sslh-main.c index 60fe6ce..4cd6def 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -249,7 +249,7 @@ static void setup_sni_hostnames(struct proto *p, config_setting_t* sni_hostnames #ifdef LIBCONFIG static int config_protocols(config_t *config, struct proto **prots) { - config_setting_t *setting, *prot, *probes, *sni_hostnames; + config_setting_t *setting, *prot, *patterns, *sni_hostnames; const char *hostname, *port, *name; int i, num_prots; struct proto *p, *prev = NULL; @@ -273,34 +273,26 @@ static int config_protocols(config_t *config, struct proto **prots) resolve_split_name(&(p->saddr), hostname, port); + p->probe = get_probe(name); + if (!p->probe) { + fprintf(stderr, "line %d: %s: probe unknown\n", config_setting_source_line(prot), name); + exit(1); + } - probes = config_setting_get_member(prot, "probe"); - if (probes) { - if (config_setting_is_array(probes)) { - /* If 'probe' is an array, setup a regex probe using the - * array of strings as pattern */ - - setup_regex_probe(p, probes); - - } else { - /* if 'probe' is 'builtin', set the probe to the - * appropriate builtin protocol */ - if (!strcmp(config_setting_get_string(probes), "builtin")) { - p->probe = get_probe(name); - if (!p->probe) { - fprintf(stderr, "%s: no builtin probe for this protocol\n", name); - exit(1); - } - } else { - fprintf(stderr, "%s: illegal probe name\n", name); - exit(1); - } + /* Probe-specific options: regex patterns */ + if (!strcmp(name, "regex")) { + patterns = config_setting_get_member(prot, "regex_patterns"); + if (patterns && config_setting_is_array(patterns)) { + setup_regex_probe(p, patterns); } } - sni_hostnames = config_setting_get_member(prot, "sni_hostnames"); - if (sni_hostnames && config_setting_is_array(sni_hostnames)) { - setup_sni_hostnames(p, sni_hostnames); + /* Probe-specific options: SNI hostnames */ + if (!strcmp(name, "sni")) { + sni_hostnames = config_setting_get_member(prot, "sni_hostnames"); + if (sni_hostnames && config_setting_is_array(sni_hostnames)) { + setup_sni_hostnames(p, sni_hostnames); + } } } } diff --git a/sslh.pod b/sslh.pod index c0ce606..a90d4bd 100644 --- a/sslh.pod +++ b/sslh.pod @@ -51,14 +51,10 @@ and the list of protocols). The configuration file makes it possible to specify protocols using regular expressions: a list of regular -expressions is given as the I parameter, and if the +expressions is given as the I parameter, and if the first packet received from the client matches any of these expressions, B connects to that protocol. -Alternatively, the I parameter can be set to -"builtin", to use the compiled probes which are much faster -than regular expressions. - =head2 Probing protocols When receiving an incoming connection, B will read the