Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

outbound: get_mx overhaul, logging improvements #3322

Merged
merged 11 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,35 @@
- when using message-stream, don't send default options #3290
- auth_base: enable disabling constrain_sender at runtime #3298
- auth_base: skip constrain_sender when auth user has no domain #3319
- rcpt_to.host_list: add connection ID to log messages #3322
- connection: support IPv6 when setting remote.is_private #3295
- in setTLS, replace forEach with for...of
- NOTE: remove a handful of 3.0 sunset property names #3315
- outbound/mx_lookup: make it async/await
- outbound/mx_lookup: deleted. Logic moved into net_utils #3322
- outbound: emit log message when ignoring local MX #3285
- outbound: pass in config when initiating txn #3315
- outbound: minor es6 updates #3315
- outbound: minor es6 updates #3315, #3322
- outbound: logging improvements #3322
- was: [-] [core] [outbound] Failed to get socket: Outbound connection error: Error: connect ECONNREFUSED 172.16.16.14:25
- now: [A63B62DF-F3B8-4096-8996-8CE83494A188.1.1] [outbound] Failed to get socket: connect ECONNREFUSED 172.16.16.14:25
- shorter logger syntax: logger.loginfo -> logger.info
- outbound: remove log prefixes of `[outbound] `, no longer needed
- logger: don't load outbound (race condition). Instead, set name property #3322
- logger: extend add_log_methods to Classes (connection, plugins, hmail) #3322
- logger: when logging via `logger` methods, use short names #3322
- outbound: delete try_deliver_host. Use net_utils to resolve MX hosts to IPs #3322
- outbound: remove config setting ipv6_enabled #3322
- outbound: remove undocumented use of send_email with arity of 2. #3322
- outbound: encapsulate force_tls logic into get_force_tls #3322
- queue/lmtp: refactored for DRY and improved readability #3322
- mail_from.resolvable: refactored, leaning on improved net_utils #3322
- fixes haraka/haraka-net-utils#88

#### Fixed

- fix(logger): refactor add_log_methods, don't set extra `loglog*` names
- doc(connection): update rfc7001 URL
- fix(bin/haraka): list NPM installed plugin #3310
- fix(bin/haraka): get hook list from doc/Plugins #3306
- fix(outbound): call cb even if no MX is found #3294
Expand Down
2 changes: 1 addition & 1 deletion bin/haraka
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@
msg = fs.readFileSync(parsed.message);
}
catch (e) {
logger.logcrit(e.message);
logger.crit(e.message);
logger.dump_logs(1);
}
}
Expand All @@ -415,11 +415,11 @@
port: 1234,
},
destroy () {},
on (event, done) {},

Check warning on line 418 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'event' is defined but never used

Check warning on line 418 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'done' is defined but never used

Check warning on line 418 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'event' is defined but never used

Check warning on line 418 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'done' is defined but never used
end () {
process.exit();
},
write (buf) {},

Check warning on line 422 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'buf' is defined but never used

Check warning on line 422 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'buf' is defined but never used
resume () {},
pause () {},
}
Expand Down Expand Up @@ -575,13 +575,13 @@
if (!hp) throw "No listen address in smtp.ini";
// console.log("Connecting to " + listen_addrs[0]);
const sock = net.connect(hp[2], hp[1], function () {
sock.once('data', function (data) {

Check warning on line 578 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'data' is defined but never used

Check warning on line 578 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'data' is defined but never used
// this is the greeting. Ignore it...
sock.write(`INTERNALCMD ${key ? (`key:${key} `) : ''}${cmd}\r\n`);
sock.once('data', function (data2) {
console.log(data2.toString().replace(/\r?\n$/, ''));
sock.write('QUIT\r\n');
sock.once('data', function (data3) {

Check warning on line 584 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'data3' is defined but never used

Check warning on line 584 in bin/haraka

View workflow job for this annotation

GitHub Actions / lint / lint

'data3' is defined but never used
sock.end();
})
});
Expand Down
6 changes: 4 additions & 2 deletions config/mail_from.is_resolvable.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
timeout=29
allow_mx_ip=0
reject_no_mx=1
allow_mx_ip=false
re_bogus_ip=^(?:0\.0\.0\.0|255\.255\.255\.255|127\.)

[reject]
no_mx=true
2 changes: 0 additions & 2 deletions config/outbound.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

; maxTempFailures (default: 13)

; ipv6_enabled (default: false)

; load_pid_queue
; flush_queue

Expand Down
19 changes: 3 additions & 16 deletions connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
self.fail();
});

self.client.on('close', has_error => {

Check warning on line 176 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'has_error' is defined but never used

Check warning on line 176 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'has_error' is defined but never used
if (self.state >= states.DISCONNECTING) return;
self.remote.closed = true;
self.loginfo('client dropped connection', log_data);
Expand Down Expand Up @@ -205,7 +205,7 @@

const ha_list = net.isIPv6(self.remote.ip) ? haproxy_hosts_ipv6 : haproxy_hosts_ipv4;

if (ha_list.some((element, index, array) => {

Check warning on line 208 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'index' is defined but never used

Check warning on line 208 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'array' is defined but never used

Check warning on line 208 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'index' is defined but never used

Check warning on line 208 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'array' is defined but never used
return ipaddr.parse(self.remote.ip).match(element[0], element[1]);
})) {
self.proxy.allowed = true;
Expand Down Expand Up @@ -689,7 +689,7 @@
}
/////////////////////////////////////////////////////////////////////////////
// SMTP Responses
connect_init_respond (retval, msg) {

Check warning on line 692 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'retval' is defined but never used

Check warning on line 692 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'msg' is defined but never used

Check warning on line 692 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'retval' is defined but never used

Check warning on line 692 in connection.js

View workflow job for this annotation

GitHub Actions / lint / lint

'msg' is defined but never used
// retval and message are ignored
this.logdebug('running connect_init_respond');
plugins.run_hooks('lookup_rdns', this);
Expand Down Expand Up @@ -1454,7 +1454,7 @@
return received_header;
}
auth_results (message) {
// http://tools.ietf.org/search/rfc7001
// https://datatracker.ietf.org/doc/rfc7001/
const has_tran = !!((this.transaction?.notes));

// initialize connection note
Expand Down Expand Up @@ -1784,7 +1784,7 @@
});
break;
default:
outbound.send_email(this.transaction, (retval2, msg2) => {
outbound.send_trans_email(this.transaction, (retval2, msg2) => {
if (!msg2) msg2 = this.queue_msg(retval2, msg);
switch (retval2) {
case constants.ok:
Expand Down Expand Up @@ -1895,17 +1895,4 @@
return new Connection(client, server, cfg);
}

// add logger methods to Connection:
for (const key in logger) {
if (!/^log\w/.test(key)) continue;
Connection.prototype[key] = (function (level) {
return function () {
// pass the connection instance to logger
const args = [ this ];
for (let i=0, l=arguments.length; i<l; i++) {
args.push(arguments[i]);
}
logger[level].apply(logger, args);
};
})(key);
}
logger.add_log_methods(Connection)
28 changes: 7 additions & 21 deletions docs/Logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,13 @@ Logging conventions within Haraka

This section pertains to the built in logging. For log plugins like ([haraka-plugin-syslog](https://github.com/haraka/haraka-plugin-syslog)), refer to the plugin's docs.

See also
------------------
[https://github.com/haraka/Haraka/pull/119](https://github.com/haraka/Haraka/pull/119)

The logline by default will be in the form of:

[level] [uuid] [origin] message

Where origin is "core" or the name of the plugin which
triggered the message, and "uuid" is the ID of the
connection associated with the message.
Where origin is "core" or the name of the plugin which triggered the message, and "uuid" is the ID of the connection associated with the message.

When calling a log method on logger, you should provide the
plugin object and the connection object anywhere in the arguments
When calling a log method on logger, you should provide the plugin object and the connection object anywhere in the arguments
to the log method.

logger.logdebug("i like turtles", plugin, connection);
Expand All @@ -39,27 +32,21 @@ Will yield, for example,

[DEBUG] [7F1C820F-DC79-4192-9AA6-5307354B20A6] [dnsbl] i like turtles

If you call the log method on the connection object, you can
forego the connection as argument:
If you call the log method on the connection object, you can forego the connection as argument:

connection.logdebug("turtles all the way down", plugin);

and similarly for the log methods on the plugin object:

plugin.logdebug("he just really likes turtles", connection);

failing to provide a connection and/or plugin object will leave
the default values in the log (currently "core").
failing to provide a connection and/or plugin object will leavethe default values in the log (currently "core").

This is implemented by testing for argument type in
the logger.js log\* method. objects-as-arguments are then sniffed
to try to determine if they're a connection or plugin instance.
This is implemented by testing for argument type in the logger.js log\* method. objects-as-arguments are then sniffed to try to determine if they're a connection or plugin instance.

### Log formats

Apart from the default log format described above, Haraka also supports logging
as [`logfmt`](https://brandur.org/logfmt) and JSON. These can be used by
changing the `format` attribute in `log.ini` to the desired format, e.g.:
Apart from the default log format described above, Haraka also supports logging as [`logfmt`](https://brandur.org/logfmt) and JSON. These can be used by changing the `format` attribute in `log.ini` to the desired format, e.g.:

```ini
; format=default
Expand All @@ -77,8 +64,7 @@ And the same line formatted as JSON:
{"level":"PROTOCOL","uuid":"9FF7F70E-5D57-435A-AAD9-EA069B6159D9.1","source":"core","message":"S: 354 go ahead, make my day"}
```

Any objects passed to the log methods will also have their properties included
in the log line. For example, using `logfmt`:
Any objects passed to the log methods will also have their properties included in the log line. For example, using `logfmt`:

level=NOTICE uuid=9FF7F70E-5D57-435A-AAD9-EA069B6159D9.1 source=core message=disconnect ip=127.0.0.1 rdns=Unknown helo=3h2dnz8a0if relay=N early=N esmtp=N tls=N pipe=N errors=0 txns=1 rcpts=1/0/0 msgs=1/0/0 bytes=222 lr="" time=0.052

Expand Down
5 changes: 0 additions & 5 deletions docs/Outbound.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ Within `tls.ini` you can specify global options for the values `ciphers`, `minVe
ciphers=!DES
```

* `ipv6_enabled`

When this has a "true" value inside (usually a `1`), it defaults to an 'AAAA'
lookup first for each MX record, and uses those hosts to send email via.

* `always_split`

Default: false. By default, Haraka groups message recipients by domain so that
Expand Down
2 changes: 2 additions & 0 deletions docs/plugins/bounce.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ section of `config/bounce.ini`:

Some features can have rejections disabled in the [reject] section.

```ini
[check]
reject_all=false
single_recipient=true
Expand All @@ -22,6 +23,7 @@ Some features can have rejections disabled in the [reject] section.
empty_return_path=true
bounce_spf=false
non_local_msgid=false
```

## Features

Expand Down
10 changes: 5 additions & 5 deletions haraka.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ exports.version = JSON.parse(

process.on('uncaughtException', err => {
if (err.stack) {
err.stack.split("\n").forEach(line => logger.logcrit(line));
err.stack.split("\n").forEach(line => logger.crit(line));
}
else {
logger.logcrit(`Caught exception: ${JSON.stringify(err)}`);
logger.crit(`Caught exception: ${JSON.stringify(err)}`);
}
logger.dump_and_exit(1);
});
Expand All @@ -52,7 +52,7 @@ signals.forEach((sig) => {
const [, filename] = process.argv;
process.title = path.basename(filename, '.js');

logger.lognotice(`${sig} received`);
logger.notice(`${sig} received`);
logger.dump_and_exit(() => {
if (server.cluster?.isMaster) {
server.performShutdown();
Expand All @@ -65,7 +65,7 @@ signals.forEach((sig) => {
});

process.on('SIGHUP', () => {
logger.lognotice('Flushing the temp fail queue');
logger.notice('Flushing the temp fail queue');
server.flushQueue();
});

Expand All @@ -74,7 +74,7 @@ process.on('exit', code => {
const [, filename] = process.argv;
process.title = path.basename(filename, '.js');

logger.lognotice('Shutting down');
logger.notice('Shutting down');
logger.dump_logs();
});

Expand Down
8 changes: 4 additions & 4 deletions host_pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class HostPool {
self.dead_hosts[key] = true;

function cb_if_still_dead () {
logger.logwarn(`${host} ${key} is still dead, will retry in ${self.retry_secs} secs`);
logger.warn(`${host} ${key} is still dead, will retry in ${self.retry_secs} secs`);
self.dead_hosts[key] = true;
// console.log(1);
setTimeout(() => {
Expand All @@ -71,7 +71,7 @@ class HostPool {

function cb_if_alive () {
// console.log(2);
logger.loginfo(`${host} ${key} is back! adding back into pool`);
logger.info(`${host} ${key} is back! adding back into pool`);
delete self.dead_hosts[key];
}

Expand All @@ -90,7 +90,7 @@ class HostPool {
probe_dead_host (
host, port, cb_if_still_dead, cb_if_alive
){
logger.loginfo(`probing dead host ${host}:${port}`);
logger.info(`probing dead host ${host}:${port}`);

const connect_timeout_ms = 200; // keep it snappy
let s;
Expand Down Expand Up @@ -162,7 +162,7 @@ class HostPool {
return host;
}
else {
logger.logwarn(
logger.warn(
`no working hosts found, retrying a dead one, config (probably from smtp_forward.forwarding_host_pool) is '${this.hostports_str}'`);
this.last_i = first_i;
return this.hosts[first_i];
Expand Down
Loading
Loading