Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
return next();
}
// step 1: get a domain name from whatever info is available
var domain = plugin.get_domain(hook, connection, params);
if (!domain) {
connection.logdebug(plugin, "domain detect failed on hook: " + hook);
return next();
}
if (!/\./.test(domain)) {
connection.results.add(plugin, {
fail: 'invalid domain: ' + domain, emit: true});
return next();
}
var org_domain = tlds.get_organizational_domain(domain);
if (!org_domain) {
connection.logerror(plugin, "no org domain from " + domain);
return next();
}
// step 2: check for whitelist
var file = plugin.cfg.domain.any;
var cr = connection.results;
if (plugin.in_list('domain', 'any', '!'+org_domain)) {
cr.add(plugin, {pass: hook +':' + file, whitelist: true, emit: true});
return next();
}
var email;
if (hook === 'mail' || hook === 'rcpt') { email = params[0].address(); }
if (email && plugin.in_list('domain', 'any', '!'+email)) {
if (!plugin.list) { plugin.list = { type: {} }; }
if (!plugin.list[type]) { plugin.list[type] = {}; }
// convert list items to LC at load (much faster than at run time)
for (var i=0; i < list.length; i++) {
if (list[i][0] === '!') { // whitelist entry
plugin.list[type][phase][list[i].toLowerCase()] = true;
continue;
}
if (/@/.test(list[i][0])) { // email address
plugin.list[type][phase][list[i].toLowerCase()] = true;
continue;
}
var d = tlds.get_organizational_domain(list[i]);
if (!d) { continue; }
plugin.list[type][phase][d.toLowerCase()] = true;
}
};
if (net_utils.is_ip_literal(helo)) {
connection.results.add(plugin, {skip: 'valid_hostname(literal)'});
return next();
}
if (!/\./.test(helo)) {
connection.results.add(plugin, {fail: 'valid_hostname(no_dot)'});
if (plugin.cfg.reject.valid_hostname) {
return next(DENY, 'Host names have more than one DNS label');
}
return next();
}
// this will fail if TLD is invalid or hostname is a public suffix
if (!tlds.get_organizational_domain(helo)) {
// Check for any excluded TLDs
const excludes = this.config.get('helo.checks.allow', 'list');
const tld = (helo.split(/\./).reverse())[0].toLowerCase();
// Exclude .local, .lan and .corp
if (tld === 'local' || tld === 'lan' || tld === 'corp' || excludes.includes('.' + tld)) {
return next();
}
connection.results.add(plugin, {fail: 'valid_hostname'});
if (plugin.cfg.reject.valid_hostname) {
return next(DENY, "HELO host name invalid");
}
return next();
}
connection.results.add(plugin, {pass: 'valid_hostname'});
return next();
domains.push(res[1]);
}
if (domains.length === 0) {
connection.loginfo(plugin,
'no domain(s) parsed from Message-ID headers');
transaction.results.add(plugin, { fail: 'Message-ID parseable' });
if (!plugin.cfg.reject.non_local_msgid) return next();
return next(DENY, `bounce with invalid Message-ID, I didn't send it.`);
}
connection.logdebug(plugin, domains);
const valid_domains=[];
for (let j=0; j < domains.length; j++) {
const org_dom = tlds.get_organizational_domain(domains[j]);
if (!org_dom) { continue; }
valid_domains.push(org_dom);
}
if (valid_domains.length === 0) {
transaction.results.add(plugin, { fail: 'Message-ID valid domain' });
if (!plugin.cfg.reject.non_local_msgid) return next();
return next(DENY, `bounce Message-ID without valid domain, I didn't send it.`);
}
return next();
/* The code below needs some kind of test to say the domain isn't local.
this would be hard to do without knowing how you have Haraka configured.
e.g. it could be config/host_list, or it could be some other way.
- hence I added the return next() above or this test can never be correct.
return next();
}
connection.results.add(plugin, {ips});
if (ips.includes(connection.remote.ip)) {
connection.results.add(plugin, {pass: 'forward_dns'});
return next();
}
// some valid hosts (facebook.com, hotmail.com, ) use a generic HELO
// hostname that resolves but doesn't contain the IP that is
// connecting. If their rDNS passed, and their HELO hostname is in
// the same domain, consider it close enough.
if (connection.results.has('helo.checks', 'pass', /^rdns_match/)) {
const helo_od = tlds.get_organizational_domain(helo);
const rdns_od = tlds.get_organizational_domain(connection.remote.host);
if (helo_od && helo_od === rdns_od) {
connection.results.add(plugin, {pass: 'forward_dns(domain)'});
return next();
}
connection.results.add(plugin, {msg: "od miss: " + helo_od + ', ' + rdns_od});
}
connection.results.add(plugin, {fail: 'forward_dns(no IP match)'});
if (plugin.cfg.reject.forward_dns) {
return next(DENY, "HELO host has no forward DNS match");
}
return next();
};
connection.results.add(plugin, {err: 'forward_dns, no ips!'});
return next();
}
connection.results.add(plugin, {ips});
if (ips.includes(connection.remote.ip)) {
connection.results.add(plugin, {pass: 'forward_dns'});
return next();
}
// some valid hosts (facebook.com, hotmail.com, ) use a generic HELO
// hostname that resolves but doesn't contain the IP that is
// connecting. If their rDNS passed, and their HELO hostname is in
// the same domain, consider it close enough.
if (connection.results.has('helo.checks', 'pass', /^rdns_match/)) {
const helo_od = tlds.get_organizational_domain(helo);
const rdns_od = tlds.get_organizational_domain(connection.remote.host);
if (helo_od && helo_od === rdns_od) {
connection.results.add(plugin, {pass: 'forward_dns(domain)'});
return next();
}
connection.results.add(plugin, {msg: "od miss: " + helo_od + ', ' + rdns_od});
}
connection.results.add(plugin, {fail: 'forward_dns(no IP match)'});
if (plugin.cfg.reject.forward_dns) {
return next(DENY, "HELO host has no forward DNS match");
}
return next();
};
connection.results.add(plugin, {fail: 'rdns_match(empty)'});
return next();
}
if (net_utils.is_ip_literal(helo)) {
connection.results.add(plugin, {fail: 'rdns_match(literal)'});
return next();
}
const r_host = connection.remote.host;
if (r_host && helo === r_host) {
connection.results.add(plugin, {pass: 'rdns_match'});
return next();
}
if (tlds.get_organizational_domain(r_host) ===
tlds.get_organizational_domain(helo)) {
connection.results.add(plugin, {pass: 'rdns_match(org_dom)'});
return next();
}
connection.results.add(plugin, {fail: 'rdns_match'});
if (plugin.cfg.reject.rdns_match) {
return next(DENY, 'HELO host does not match rDNS');
}
return next();
}
var hdr_from = connection.transaction.header.get('From');
if (!hdr_from) {
connection.transaction.results.add(plugin, {
fail: 'data(missing_from)'});
return next();
}
var hdr_addr = haddr.parse(hdr_from)[0];
if (!hdr_addr) {
connection.transaction.results.add(plugin, {
fail: 'data(unparsable_from)'
});
return next();
}
var hdr_dom = tlds.get_organizational_domain(hdr_addr.host());
var file = plugin.cfg.domain.any;
if (plugin.in_list('domain', 'any', '!'+hdr_dom)) {
connection.results.add(plugin, {
pass: file, whitelist: true, emit: true});
return next();
}
if (plugin.in_list('domain', 'any', hdr_dom)) {
connection.results.add(plugin, {
fail: file+'('+hdr_dom+')', blacklist: true, emit: true});
return next(DENY, "Email from that domain is not accepted here.");
}
connection.results.add(plugin, {msg: 'unlisted(any)' });
return next();
return next();
}
if (net_utils.is_ip_literal(helo)) {
connection.results.add(plugin, {fail: 'rdns_match(literal)'});
return next();
}
const r_host = connection.remote.host;
if (r_host && helo === r_host) {
connection.results.add(plugin, {pass: 'rdns_match'});
return next();
}
if (tlds.get_organizational_domain(r_host) ===
tlds.get_organizational_domain(helo)) {
connection.results.add(plugin, {pass: 'rdns_match(org_dom)'});
return next();
}
connection.results.add(plugin, {fail: 'rdns_match'});
if (plugin.cfg.reject.rdns_match) {
return next(DENY, 'HELO host does not match rDNS');
}
return next();
}