Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
}
if (/^SMTPUTF8/.test(smtp_client.response[line])) {
smtp_client.smtputf8 = true;
}
if (/^STARTTLS/.test(smtp_client.response[line]) && !secured) {
let hostBanned = false
let serverBanned = false
// Check if there are any banned TLS hosts
if (smtp_client.tls_options.no_tls_hosts) {
// If there are check if these hosts are in the blacklist
hostBanned = net_utils.ip_in_list(smtp_client.tls_config.no_tls_hosts, config.host);
serverBanned = net_utils.ip_in_list(smtp_client.tls_config.no_tls_hosts, smtp_client.remote_ip);
}
if (!hostBanned && !serverBanned && config.enable_tls) {
smtp_client.socket.on('secure', on_secured);
smtp_client.secured = false; // have to wait in forward plugin before we can do auth, even if capabilities are there on first EHLO
smtp_client.send_command('STARTTLS');
return;
}
}
let auth_matches = smtp_client.response[line].match(/^AUTH (.*)$/);
if (auth_matches) {
smtp_client.auth_capabilities = [];
auth_matches = auth_matches[1].split(' ');
for (let i = 0; i < auth_matches.length; i++) {
smtp_client.auth_capabilities.push(auth_matches[i].toLowerCase());
}
}
if (/^SMTPUTF8/.test(smtp_client.response[line])) {
smtp_client.smtputf8 = true;
}
if (/^STARTTLS/.test(smtp_client.response[line]) && !secured) {
let hostBanned = false
let serverBanned = false
// Check if there are any banned TLS hosts
if (smtp_client.tls_options.no_tls_hosts) {
// If there are check if these hosts are in the blacklist
hostBanned = net_utils.ip_in_list(smtp_client.tls_config.no_tls_hosts, config.host);
serverBanned = net_utils.ip_in_list(smtp_client.tls_config.no_tls_hosts, smtp_client.remote_ip);
}
if (!hostBanned && !serverBanned && config.enable_tls) {
smtp_client.socket.on('secure', on_secured);
smtp_client.secured = false; // have to wait in forward plugin before we can do auth, even if capabilities are there on first EHLO
smtp_client.send_command('STARTTLS');
return;
}
}
let auth_matches = smtp_client.response[line].match(/^AUTH (.*)$/);
if (auth_matches) {
smtp_client.auth_capabilities = [];
auth_matches = auth_matches[1].split(' ');
for (let i = 0; i < auth_matches.length; i++) {
// Check for SIZE parameter and limit
matches = r.match(/^SIZE\s+(\d+)$/);
if (matches) {
smtp_properties.max_size = matches[1];
}
// Check for AUTH
matches = r.match(/^AUTH\s+(.+)$/);
if (matches) {
smtp_properties.auth = matches[1].split(/\s+/);
}
}
}
// TLS
if (!net_utils.ip_in_list(tls_cfg.no_tls_hosts, self.todo.domain) &&
!net_utils.ip_in_list(tls_cfg.no_tls_hosts, host) &&
smtp_properties.tls && cfg.enable_tls && !secured)
{
socket.on('secure', function () {
// Set this flag so we don't try STARTTLS again if it
// is incorrectly offered at EHLO once we are secured.
secured = true;
send_command(mx.using_lmtp ? 'LHLO' : 'EHLO', mx.bind_helo);
});
return send_command('STARTTLS');
}
// IMPORTANT: we do STARTTLS before we attempt AUTH for extra security
if (!authenticated && (mx.auth_user && mx.auth_pass)) {
// We have AUTH credentials to send for this domain
if (!(Array.isArray(smtp_properties.auth) && smtp_properties.auth.length)) {
// AUTH not offered
var matches;
// Check for SIZE parameter and limit
matches = r.match(/^SIZE\s+(\d+)$/);
if (matches) {
smtp_properties.max_size = matches[1];
}
// Check for AUTH
matches = r.match(/^AUTH\s+(.+)$/);
if (matches) {
smtp_properties.auth = matches[1].split(/\s+/);
}
}
}
// TLS
if (!net_utils.ip_in_list(tls_cfg.no_tls_hosts, self.todo.domain) &&
!net_utils.ip_in_list(tls_cfg.no_tls_hosts, host) &&
smtp_properties.tls && cfg.enable_tls && !secured)
{
socket.on('secure', function () {
// Set this flag so we don't try STARTTLS again if it
// is incorrectly offered at EHLO once we are secured.
secured = true;
send_command(mx.using_lmtp ? 'LHLO' : 'EHLO', mx.bind_helo);
});
return send_command('STARTTLS');
}
// IMPORTANT: we do STARTTLS before we attempt AUTH for extra security
if (!authenticated && (mx.auth_user && mx.auth_pass)) {
// We have AUTH credentials to send for this domain
if (!(Array.isArray(smtp_properties.auth) && smtp_properties.auth.length)) {
addresses.forEach(addr => {
// Handle MX records that are IP addresses
// This is invalid - but a lot of MTAs allow it.
if (net_utils.get_ipany_re('^\\[','\\]$','').test(addr.exchange)) {
connection.logwarn(plugin, domain + ': invalid MX ' +
addr.exchange);
if (c.allow_mx_ip) {
records[addr.exchange] = 1;
}
return;
}
pending_queries++;
net_utils.get_ips_by_host(addr.exchange, (err2, addresses2) => {
pending_queries--;
if (!txn) return;
if (err2 && err2.length === 2) {
results.add(plugin, {msg: err2[0].message});
connection.logdebug(plugin, domain + ': MX ' +
addr.priority + ' ' + addr.exchange +
' => ' + err2[0].message);
exports.dynamic = function (next, connection, helo) {
const plugin = this;
if (plugin.should_skip(connection, 'dynamic')) { return next(); }
// Skip if no dots or an IP literal or address
if (!/\./.test(helo)) {
connection.results.add(plugin, {skip: 'dynamic(no dots)'});
return next();
}
if (net_utils.get_ipany_re('^\\[?(?:IPv6:)?','\\]?$','').test(helo)) {
connection.results.add(plugin, {skip: 'dynamic(literal)'});
return next();
}
if (net_utils.is_ip_in_str(connection.remote.ip, helo)) {
connection.results.add(plugin, {fail: 'dynamic'});
if (plugin.cfg.reject.dynamic) {
return next(DENY, 'HELO is dynamic');
}
return next();
}
connection.results.add(plugin, {pass: 'dynamic'});
return next();
}
exports.bare_ip = function (next, connection, helo) {
const plugin = this;
if (plugin.should_skip(connection, 'bare_ip')) { return next(); }
// RFC 2821, 4.1.1.1 Address literals must be in brackets
// RAW IPs must be formatted: "[1.2.3.4]" not "1.2.3.4" in HELO
if (net_utils.get_ipany_re('^(?:IPv6:)?','$','').test(helo)) {
connection.results.add(plugin, {fail: 'bare_ip(invalid literal)'});
if (plugin.cfg.reject.bare_ip) {
return next(DENY, "Invalid address format in HELO");
}
return next();
}
connection.results.add(plugin, {pass: 'bare_ip'});
return next();
}
addresses.forEach(addr => {
// Handle MX records that are IP addresses
// This is invalid - but a lot of MTAs allow it.
if (net_utils.get_ipany_re('^\\[','\\]$','').test(addr.exchange)) {
connection.logwarn(plugin, domain + ': invalid MX ' +
addr.exchange);
if (c.allow_mx_ip) {
records[addr.exchange] = 1;
}
return;
}
pending_queries++;
net_utils.get_ips_by_host(addr.exchange, (err2, addresses2) => {
pending_queries--;
if (!txn) return;
if (err2 && err2.length === 2) {
results.add(plugin, {msg: err2[0].message});
connection.logdebug(plugin, domain + ': MX ' +
addr.priority + ' ' + addr.exchange +
' => ' + err2[0].message);
check_results();
return;
}
connection.logdebug(plugin, domain + ': MX ' + addr.priority +
' ' + addr.exchange + ' => ' + addresses2);
for (let i=0; i < addresses2.length; i++) {
// Ignore anything obviously bogus
if (net.isIPv4(addresses2[i])){
if (plugin.re_bogus_ip.test(addresses2[i])) {
exports.implicit_mx = function (connection, domain, mxDone) {
const plugin = this;
const txn = connection.transaction;
net_utils.get_ips_by_host(domain, (err, addresses) => {
if (!txn) return;
if (!addresses || !addresses.length) {
txn.results.add(plugin, {fail: 'has_fwd_dns'});
return mxDone(((plugin.cfg.main.reject_no_mx) ? DENY : DENYSOFT),
'No MX for your FROM address');
}
connection.logdebug(plugin, domain + ': A/AAAA => ' + addresses);
let records = {};
for (let i=0; i < addresses.length; i++) {
const addr = addresses[i];
// Ignore anything obviously bogus
if (net.isIPv4(addr)){
if (plugin.re_bogus_ip.test(addr)) {
connection.logdebug(plugin, domain + ': discarding ' + addr);
continue;
// Set-up timer
let timed_out = false;
const timer = setTimeout(() => {
timed_out = true;
const err = new Error('timeout resolving: ' + host);
err.code = dns.TIMEOUT;
plugin.logerror(err);
return cb(err);
}, (plugin.cfg.main.dns_timeout || 30) * 1000);
// fully qualify, to ignore any search options in /etc/resolv.conf
if (!/\.$/.test(host)) { host = host + '.'; }
// do the queries
net_utils.get_ips_by_host(host, (errs, ips) => {
// results is now equals to: {queryA: 1, queryAAAA: 2}
if (timed_out) { return; }
if (timer) { clearTimeout(timer); }
let err = '';
for (const error of errs) {
switch (error.code) {
case dns.NODATA:
case dns.NOTFOUND:
case dns.SERVFAIL:
continue;
default:
err = `${err}, ${error.message}`;
}
}
if (!ips.length && err) { return cb(err, ips); }
// plugin.logdebug(plugin, host + ' => ' + ips);