Add support for specifying outbound source IP address (i.e. for multi-homed servers)
cipriancraciun opened this issue · comments
In case of multi-homed servers (having multiple public interfaces, with multiple default routes but using routing policies) it would be useful to have an option to specify the local IP address that should be used to connect from (i.e. bind(local_address)
then connect(remote_address)
).
This should be configurable through the configuration file, for example: smtp_local_address = "9.9.9.9"
.
In fact, by default this IP address should be initialized with the IP from smtp_address
, as most likely the IP used to accept inbound SMTP connections should also be used for outbound SMTP connections. (And in case that is missing, just use 0.0.0.0
as it currently is.)
Looking at the source code, I assume that one could just change:
https://github.com/albertito/chasquid/blob/master/internal/courier/smtp.go#L128
conn, err := net.DialTimeout("tcp", mx+":"+*smtpPort, smtpDialTimeout)
with
localAddress = ...
remoteAddress, err := net.ResolveTCPAddr("tcp", mx+":"+*smtpPort)
...
conn, err := net.DialTcp("tcp", localAddress, remoteAddress)
...
However that loses the smtpDialTimeout
functionality.
Or perhaps using the net.Dialer
type, although that might be somewhat more complex.
Sorry I didn't reply before, I thought I had :(
Thanks for the suggestion!
I need to read up/refresh my knowledge on route policies a bit, think about the implications of this more carefully. It's not clear to me this is worth the complexity, but it definitely could be.
If there's more information that would help prioritize this higher, (e.g. more folks running into this, no possible workarounds, etc.) please let me know.
Thank you!
I need to read up/refresh my knowledge on route policies a bit, think about the implications of this more carefully. It's not clear to me this is worth the complexity, but it definitely could be.
In essence chasquid
shouldn't care at all about the routing; using (Linux) routing policies was just an example how one could achieve this (and doesn't directly involve chasquid
), there are also other techniques (such as a router downstream switching the provider based on the source IP).
Just bind
-ing on a given IP (as opposed to the default 0.0.0.0
) should be enough to implement this feature.
If there's more information that would help prioritize this higher, (e.g. more folks running into this, no possible workarounds, etc.) please let me know.
I'm not sure many would use this feature (as many servers have one IP and one default route). Regarding work-arounds there are, but they aren't as straight-forward as having chasquid
bind on the desired IP.
I think this should work to implement it with a context timeout:
d := net.Dialer{
// LocalAddr = ...,
Timeout: smtpDialTimeout,
}
conn, err := d.Dial("tcp", mx+":"+*smtpPort)
if err != nil {
return a.tr.Errorf("Could not dial: %v", err), false
}
defer conn.Close()
EDIT: replaced the context with Dialer.Timeout