-
Notifications
You must be signed in to change notification settings - Fork 51
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
Implement header "From" rewriting #96
Conversation
This adds header From rewriting when enabled in dma.conf with REWRITEFROM. The original From header is added as "X-Original-From". The maximum length of the From header is limited to 10 lines as defined by MSG_HDR_FROM_MAX due to static variable allocation. The rewrite function fails if the address part of the From header is not in a single line as it uses a simple strncmp. This could be improved by refactoring parse_addrs() into a more generic address parsing function that returns pointers to the start and end of a valid address in the passed string, so the rewrite function could just replace the string between those 2 pointers (inserting line continuations before and after the address if the address happened to be split into multiple lines). Nevertheless, the current simplified rewriting function will fail gracefully in this case. If the rewrite fails to find the From address in the header line, the header is not rewritten, but X-Original-From is still added. This can be changed via a later commit to on failure replace it with the envelope-from address and discard the original From line. This will ensure rewriting always takes place, but will not preserve the From address comment sent by the client on failure to rewrite.
Instead of passing the original From unchanged if rewriting fails, replace it with envelope-from anyway, to guarantee the message will get delivered. The original From will be included as X-Original-From so it can be checked why the rewrite failed later.
Added a commit that addresses this issue:
This commit will make it replace the From with envelope-from even when the rewrite fails. |
Why do we have to store the headers in the queue structure? |
You're right, it's a global variable so it can be accessed from any function. I was looking at issues #16 and #21, it seems like what's needed is a more generalized rewrite function. rewrite_header_from could easily be rewritten to work on any header. The bigger issue I see is that by using static variable allocation like I used here, the from_lines variable needs to be initialized to the maximum possible from lines size, which uses quite some memory (10k bytes from_lines + 10k bytes rewritten_from_lines = 20k bytes). That would increase linearly as more variables are needed for To, Cc, Bcc. The better way would be to use dynamic allocation, but would require rewriting most of the rewriting code as it is in this PR. |
I mean, can we just rewrite the header on the fly, without storing it?
…On 17/04/2021 05:37, Jernej Jakob wrote:
You're right, it's a global variable so it can be accessed from any
function.
I was looking at issues #16
<#16> and #21
<#21>, it seems like what's
needed is a more generalized rewrite function. rewrite_header_from
could easily be rewritten to work on any header. The bigger issue I
see is that by using static variable allocation like I used here, the
from_lines variable needs to be initialized to the maximum possible
from lines size, which uses quite some memory (10k bytes from_lines +
10k bytes rewritten_from_lines = 20k bytes). That would increase
linearly as more variables are needed for To, Cc, Bcc. The better way
would be to use dynamic allocation, but would require rewriting most
of the rewriting code as it is in this PR.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#96 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABLOOYU55AI6GTTXA7BCEDTJFQEZANCNFSM42ZTYL2Q>.
|
It might be possible to rewrite it on the fly, I'd need to try implementing it. It needs to be stored at least to add the X-Original-From header, which is good to have if there's a bug in the rewrite code, we can see what the original header was. |
I guess I don't understand. In my mind, we see the From: line, then
insert a X-Original-From: (maybe with newline continuation), then the
contents of the From line, and all following continuation lines. Is
there something we need to read first completely, before we can issue
the new From?
…On 17/04/2021 17:17, Jernej Jakob wrote:
It might be possible to rewrite it on the fly, I'd need to try
implementing it. It needs to be stored at least to add the
X-Original-From header, which is good to have if there's a bug in the
rewrite code, we can see what the original header was.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#96 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABLOO5XRJEVWRRKZPRAQE3TJICGNANCNFSM42ZTYL2Q>.
|
A header can be split into multiple lines by inserting a blank character at the beginning of the next line, for example:
The main reason being for cases where a header would exceed the maximum line length, which is 998 characters according to https://tools.ietf.org/html/rfc2822#section-2.2.3 (this is called "folding"). |
To clarify the last paragraph - it would be possible to not exceed the 998-char limit even with rewriting as we do it here, just by always folding before the rewritten address. For example:
(imagine that the original header is right at 998 chars, we need to fold both the rewritten address and X-Original-From into their own lines, as "X-Original-" is 11 additional characters that would make the line exceed the limit) |
And another example:
Could be rewritten to:
by passing the non-address lines through unchanged, stripping |
I still don't get the complication. When looking at the |
Because the point of rewriting is to rewrite just the address part of the headers, not the comments. The comment can be anything the sender wants, and it would be bad to strip it out, as it can have the sender's name, the application's name in it, etc. |
If we replaced |
#21 would also be impossible to implement without actually storing the whole header and rewriting just the address part. Okay, possible just by blindly discarding everything that isn't the address itself, but that would be very rude, and hardly satisfactory IMO. |
Doing the whole rewriting is too complicated and will likely introduce bugs. I think we either replace the From: address, or not do it at all. |
I'll come up with a working on-the-fly rewrite branch in any case when I get to it. Parsing the address from the header (with all the weirdness aroud folding etc.) is already in the code in parse_addrs, so there's not much possibility of going wrong there, and I won't be touching it. So this branch can stay as a WIP/PoC (or someone can already use it on his systems as I am). |
If you ever get around to implementing this, consider also applying the same treatment to the "To" header (I'm currently seeing rejected mails because mails are generated with "To: root" which dma passes without modification and which my exim rejects. |
If it's for mails from cron, you can set the MAILTO variable in the crontab ( |
It was for cron, sudo, netdata and maybe some others.
Yeah, I have the same alias and I had picked DMA because it would rewrite the envelope to be correct.
I'm using Exim with
No worries, for now I switched to nullmailer which does support qualifying plain usernames in the headers (it only supports adding the mailname, not applying aliases on them for full rewriting, but I ended up doing the rewriting on the exim side instead). |
This adds header From rewriting when enabled in dma.conf with REWRITEFROM.
The original From header is added as "X-Original-From".
The maximum length of the From header is limited to 10 lines as defined
by MSG_HDR_FROM_MAX due to static variable allocation.
The rewrite function fails if the address part of the From header is
not in a single line as it uses a simple strncmp. This could be improved
by refactoring parse_addrs() into a more generic address parsing
function that returns pointers to the start and end of a valid address
in the passed string, so the rewrite function could just replace the
string between those 2 pointers (inserting line continuations before and
after the address if the address happened to be split into multiple
lines). Nevertheless, the current simplified rewriting function will
fail gracefully in this case.
If the rewrite fails to find the From address in the header line,
the header is not rewritten, but X-Original-From is still added.
This can be changed via a later commit to on failure replace it with the
envelope-from address and discard the original From line. This will ensure
rewriting always takes place, but will not preserve the From address comment
sent by the client on failure to rewrite.