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

Multiple outbound ip issue in 3.0.4 #3410

Open
gamalan opened this issue Sep 27, 2024 · 2 comments
Open

Multiple outbound ip issue in 3.0.4 #3410

gamalan opened this issue Sep 27, 2024 · 2 comments

Comments

@gamalan
Copy link

gamalan commented Sep 27, 2024

Describe the bug

Before Haraka 3.0.4. Using multiple outbound could be set using get_mx_hook or using notes.outbound_ip. Which is helpful, because we could set it without messing the mx lookup in haraka itself. But in the haraka 3.0.4 it's being deprecated. While it's understandable to be deprecated, this also means we need to use get_mx_hook. @baudehlo give example in #442

var outbound = require('./outbound');

var i = 0;
var ips = ['127.0.0.1', '127.0.0.2', '127.0.0.3'];

exports.hook_get_mx = function (next, hmail, domain) {
    outbound.lookup_mx(domain, function (err, mxs) {
        if (err) return next(DENY, err);
        // TODO: decide which outbound IP to use. For argument I'll use round-robin here.
        mxs.forEach(function (mx) {
            mx.bind = ips[i];
            i++;
            if (i == ips.length) i = 0;
        });
        next(OK, mxs);
    })    
}

Which is somehow outbound.lookup_mx doesn't exist anymore in 3.0.4. While using notes.outbound_ip is still possible it also produce some error. Namely it fail to bind the socket first time, but it works in subsequent try, which introducing a delay in delivery process.

Sep 26 22:46:26 dev haraka[199655]: [ERROR] [A5940E5C-D15C-4ECC-8C72-3A60B5D22404.1.1] [outbound] notes.outbound_ip is deprecated. Use get_mx.bind instead!
Sep 26 22:46:26 dev haraka[199655]: [ERROR] [A5940E5C-D15C-4ECC-8C72-3A60B5D22404.1.1] [outbound] Failed to get socket: bind EINVAL 103.171.18.245
Sep 26 22:46:26 dev haraka[199655]: [ERROR] [A5940E5C-D15C-4ECC-8C72-3A60B5D22404.1.1] [outbound] notes.outbound_ip is deprecated. Use get_mx.bind instead!
Sep 26 22:46:26 dev haraka[199657]: [NOTICE] [EE34D140-3BF5-41A6-B694-ABD6E069CF2C] [core] connect ip=::1 port=37980 local_ip=::1 local_port=587
Sep 26 22:46:26 dev haraka[199655]: [INFO] [A5940E5C-D15C-4ECC-8C72-3A60B5D22404.1.1] [outbound] secured verified=true cipher=TLS_AES_256_GCM_SHA384 version=TLSv1.3 cn=mx.google.com organization="" issuer="Google Trust Services" expires="Nov 18 07:12:13 2024 GMT" fingerprint=E9:92:77:5E:10:16:BB:D6:79:E7:4D:18:0F:8A:C0:86:AA:B0:FD:61
Sep 26 22:46:27 dev haraka[199655]: [NOTICE] [A5940E5C-D15C-4ECC-8C72-3A60B5D22404.1.1] [outbound]  delivered file=1727405185980_1727405185980_0_199655_WGub1r_2_dev.kirimemail.com domain=gmail.com host=142.251.175.27 ip=142.251.175.27 port=25 mode=SMTP tls=Y auth=N response="OK  1727405187 d9443c01a7336-20b37e82821si10966165ad.606 - gsmtp" delay=1.8 fails=0 rcpts=1/0/0

My question is,

  1. Is this normal behavior when binding to specific ip, or there are issue in sockaddr library?
  2. What recommended binding to specific ip, in version 3.0.4 without messing too much with haraka internal get_mx process?

System Info

Please report your OS, Node version, and Haraka version by running this shell script on your Haraka server and replacing this section with the output.

Haraka Haraka.js — Version: 3.0.4/ae409b48
Node v20.17.0
OS Linux dev.kirimemail.com 5.10.0-32-amd64 #1 SMP Debian 5.10.223-1 (2024-08-10) x86_64 GNU/Linux
openssl OpenSSL 1.1.1w 11 Sep 2023
@msimerson
Copy link
Member

msimerson commented Sep 28, 2024

Hi @gamalan , glad you noticed that deprecation warning. I was hoping it would surface someone(s) who actually used that feature. Answers:

  1. I don't know.
  2. The old functionality of lookup_mx is now handled by haraka-net-utils.get_mx. So you could instead do something like this:
const nu = require('haraka-net-utils')
let mxes = await nu.get_mx('gmail.com')
for const (mx of mxes) {
  mx.bind = 'X.X.X.X'  // maybe with conditional logic
}
// the rest of your code

Example 1

 node
Welcome to Node.js v22.7.0.
> const nu = require('haraka-net-utils')
> await nu.get_mx('gmail.com')
[
  HarakaMx {
    exchange: 'alt3.gmail-smtp-in.l.google.com',
    priority: 30,
    from_dns: 'gmail.com',
    bind_helo: 'home.simerson.net'
  },
  HarakaMx {
    exchange: 'gmail-smtp-in.l.google.com',
    priority: 5,
    from_dns: 'gmail.com',
    bind_helo: 'home.simerson.net'
  },
  HarakaMx {
    exchange: 'alt2.gmail-smtp-in.l.google.com',
    priority: 20,
    from_dns: 'gmail.com',
    bind_helo: 'home.simerson.net'
  },
  HarakaMx {
    exchange: 'alt4.gmail-smtp-in.l.google.com',
    priority: 40,
    from_dns: 'gmail.com',
    bind_helo: 'home.simerson.net'
  },
  HarakaMx {
    exchange: 'alt1.gmail-smtp-in.l.google.com',
    priority: 10,
    from_dns: 'gmail.com',
    bind_helo: 'home.simerson.net'
  }
]

One of the issues you might encounter is that you need to know if the remote IP is IPv4 or IPv6, and use that to choose which local IP you bind to. You can do that as well (something that's far too late to set a note for):

Example 2

> const nu = require('haraka-net-utils')
> const mxes = await nu.get_mx('gmail.com')
> const ips = await nu.resolve_mx_hosts(mxes)
> console.log(ips)
[
  {
    exchange: '2607:f8b0:4023:1004::1a',
    priority: 10,
    from_dns: 'alt1.gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  },
  {
    exchange: '142.250.115.27',
    priority: 10,
    from_dns: 'alt1.gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  },
  {
    exchange: '2607:f8b0:4001:c56::1b',
    priority: 30,
    from_dns: 'alt3.gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  },
  {
    exchange: '142.250.152.26',
    priority: 30,
    from_dns: 'alt3.gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  },
  {
    exchange: '2607:f8b0:400e:c03::1a',
    priority: 5,
    from_dns: 'gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  },
  {
    exchange: '74.125.195.26',
    priority: 5,
    from_dns: 'gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  },
  {
    exchange: '2607:f8b0:4003:c04::1a',
    priority: 20,
    from_dns: 'alt2.gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  },
  {
    exchange: '108.177.104.27',
    priority: 20,
    from_dns: 'alt2.gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  },
  {
    exchange: '2607:f8b0:4023:1::1b',
    priority: 40,
    from_dns: 'alt4.gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  },
  {
    exchange: '172.253.113.27',
    priority: 40,
    from_dns: 'alt4.gmail-smtp-in.l.google.com',
    bind_helo: 'home.simerson.net'
  }
]

Does that help?

@gamalan
Copy link
Author

gamalan commented Sep 28, 2024

@msimerson that helps. need to update our internal plugin then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants