Permalink
Browse files

Add new proto_mismatch check to helo.checks

  • Loading branch information...
1 parent e1b4388 commit 68903260e63ab9cccf3c2cb2b8bf32d350158205 @smfreegard smfreegard committed Jun 26, 2014
Showing with 94 additions and 1 deletion.
  1. +3 −0 config/helo.checks.ini
  2. +5 −0 docs/plugins/helo.checks.md
  3. +36 −1 plugins/helo.checks.js
  4. +50 −0 tests/plugins/helo.checks.js
View
@@ -14,9 +14,12 @@ forward_dns=true
rdns_match=true
; mismatch: hostname differs between EHLO invocations
mismatch=true
+; proto_mismatch: host sent EHLO but then tries to sent HELO or vice-versa
+proto_mismatch=true
[reject]
mismatch=true
+proto_mismatch=false
rdns_match=false
dynamic=false
bare_ip=false
@@ -88,6 +88,10 @@ helo.checks results can be accessed by subsequent plugins:
If HELO is called multiple times, checks if the hostname differs between
EHLO invocations.
+ * proto\_mismatch=true
+
+ If EHLO was sent and the host later tries to then send HELO or vice-versa.
+
### [reject]
For all of the checks included above, a matching key in the reject section
@@ -97,6 +101,7 @@ helo.checks results can be accessed by subsequent plugins:
[reject]
mismatch=false
+ proto_mismatch=false
rdns_match=false
dynamic=false
bare_ip=false
View
@@ -19,6 +19,9 @@ var checks = [
exports.register = function () {
var plugin = this;
+ plugin.register_hook('helo', 'proto_mismatch_smtp');
+ plugin.register_hook('ehlo', 'proto_mismatch_esmtp');
+
for (var i=0; i < checks.length; i++) {
var hook = checks[i];
plugin.register_hook('helo', hook);
@@ -38,6 +41,7 @@ exports.hook_connect = function (next, connection) {
'+check.forward_dns',
'+check.rdns_match',
'+check.mismatch',
+ '+check.proto_mismatch',
'+reject.valid_hostname',
'+reject.match_re',
@@ -48,6 +52,7 @@ exports.hook_connect = function (next, connection) {
'-reject.literal_mismatch',
'-reject.rdns_match',
'-reject.mismatch',
+ '-reject.proto_mismatch',
'+skip.private_ip',
'+skip.whitelist',
@@ -88,7 +93,9 @@ exports.should_skip = function (connection, test_name) {
var plugin = this;
var hc = connection.results.get('helo.checks');
- if (hc && hc.multi && test_name !== 'mismatch') return true;
+ if (hc && hc.multi && test_name !== 'mismatch' && test_name !== 'proto_mismatch') {
+ return true;
+ }
if (!plugin.cfg.check[test_name]) {
connection.results.add(plugin, {skip: test_name + '(config)'});
@@ -418,6 +425,34 @@ exports.forward_dns = function (next, connection, helo) {
plugin.get_a_records(helo, cb);
};
+exports.proto_mismatch = function (next, connection, helo, proto) {
+ var plugin = this;
+
+ if (plugin.should_skip(connection, 'proto_mismatch')) return next();
+
+ var prev_helo = connection.results.get('helo.checks').helo_host;
+ if (!prev_helo) return next();
+
+ if ((connection.esmtp && proto === 'smtp') ||
+ (!connection.esmtp && proto === 'esmtp'))
+ {
+ connection.results.add(plugin, {fail: 'proto_mismatch(' + proto + ')'});
+ if (plugin.cfg.reject.proto_mismatch) {
+ return next(DENY, (proto === 'smtp' ? 'HELO' : 'EHLO') + ' protocol mismatch');
+ }
+ }
+
+ return next();
+};
+
+exports.proto_mismatch_smtp = function (next, connection, helo) {
+ this.proto_mismatch(next, connection, helo, 'smtp');
+}
+
+exports.proto_mismatch_esmtp = function (next, connection, helo) {
+ this.proto_mismatch(next, connection, helo, 'esmtp');
+}
+
exports.emit_log = function (next, connection, helo) {
var plugin = this;
// Spits out an INFO log entry. Default looks like this:
@@ -78,6 +78,56 @@ exports.mismatch = {
},
};
+
+exports.proto_mismatch = {
+ setUp : _set_up,
+ tearDown : _tear_down,
+ 'disabled' : function (test) {
+ test.expect(2);
+ var outer = this;
+ var cb = function () {
+ test.equal(undefined, arguments[0]);
+ test.ok(outer.connection.results.get('helo.checks').skip.length);
+ };
+ this.plugin.init(stub, this.connection, 'helo.example.com');
+ this.plugin.cfg.check.proto_mismatch=false;
+ this.plugin.cfg.reject.proto_mismatch=true;
+ this.connection.esmtp = false;
+ this.plugin.proto_mismatch(cb, this.connection, 'any.example.com', 'esmtp');
+ test.done();
+ },
+ 'enabled=true, proto_mismatch, reject=false' : function (test) {
+ test.expect(2);
+ var outer = this;
+ var cb = function () {
+ test.equal(undefined, arguments[0]);
+ // console.log(outer.connection.results.get('helo.checks'));
+ test.ok(outer.connection.results.get('helo.checks').fail.length);
+ };
+ this.plugin.init(stub, this.connection, 'helo.example.com');
+ this.connection.esmtp = false;
+ this.plugin.cfg.check.proto_mismatch=true;
+ this.plugin.cfg.reject.proto_mismatch=false;
+ this.plugin.proto_mismatch(cb, this.connection, 'anything', 'esmtp');
+ test.done();
+ },
+ 'enabled=true, proto_mismatch, reject=true' : function (test) {
+ test.expect(2);
+ var outer = this;
+ var cb = function () {
+ test.equal(DENY, arguments[0]);
+ // console.log(outer.connection.results.get('helo.checks'));
+ test.ok(outer.connection.results.get('helo.checks').fail.length);
+ };
+ this.plugin.init(stub, this.connection, 'helo.example.com');
+ this.connection.esmtp = false;
+ this.plugin.cfg.check.proto_mismatch=true;
+ this.plugin.cfg.reject.proto_mismatch=true;
+ this.plugin.proto_mismatch(cb, this.connection, 'anything', 'esmtp');
+ test.done();
+ },
+};
+
exports.rdns_match = {
setUp : _set_up,
tearDown : _tear_down,

0 comments on commit 6890326

Please sign in to comment.