63 lines
2.3 KiB
Diff
63 lines
2.3 KiB
Diff
# UNDF: UNDF-2026-000000217
|
|
--- a/postfix/src/cleanup/cleanup_masquerade.c
|
|
+++ b/postfix/src/cleanup/cleanup_masquerade.c
|
|
@@ -52,6 +52,7 @@
|
|
#include <mail_params.h>
|
|
#include <tok822.h>
|
|
#include <quote_822_local.h>
|
|
+#include <htable.h>
|
|
|
|
/* Application-specific. */
|
|
|
|
@@ -75,6 +76,8 @@ int cleanup_masquerade_external(CLEANUP_STATE *state, VSTRING *addr,
|
|
ARGV *masq_domains)
|
|
{
|
|
char *domain;
|
|
+ /* Lazy-built hash cache for masq_domains exact matches (key=domain, value=masq) */
|
|
+ static HTABLE *masq_domain_cache = 0;
|
|
ssize_t domain_len;
|
|
char **masqp;
|
|
char *masq;
|
|
@@ -96,11 +99,26 @@ int cleanup_masquerade_external(CLEANUP_STATE *state, VSTRING *addr,
|
|
if (excluded)
|
|
return (0);
|
|
}
|
|
+
|
|
+ /*
|
|
+ * CWE-407 fix: Build a hash cache of exact-match masquerade domains on
|
|
+ * first use so we avoid O(D) scan for every address processed.
|
|
+ * Wildcard/prefix masquerade domains (those starting with '!') still
|
|
+ * require the linear scan — handle them in a second pass.
|
|
+ */
|
|
+ if (masq_domain_cache == 0) {
|
|
+ masq_domain_cache = htable_create(masq_domains->argc * 2 + 1);
|
|
+ for (char **p = masq_domains->argv; *p != 0; p++) {
|
|
+ char *m = *p;
|
|
+ int neg = 0;
|
|
+ while (*m == '!') { neg = !neg; m++; }
|
|
+ if (*m && strchr(m, '.') != 0 && !neg)
|
|
+ htable_enter(masq_domain_cache, m, m);
|
|
+ }
|
|
+ }
|
|
+
|
|
/*
|
|
- * If any parent domain matches the list of masquerade domains, replace
|
|
- * the domain in the address and terminate. If the domain matches a
|
|
- * masquerade domain, leave it alone. Order of specification matters.
|
|
+ * Fast path: O(1) hash lookup for exact-match masquerade domains.
|
|
+ * Fall through to linear scan only for prefix/negated patterns.
|
|
*/
|
|
+ {
|
|
+ char *cached = htable_find(masq_domain_cache, domain);
|
|
+ if (cached) {
|
|
+ if (msg_verbose)
|
|
+ msg_info("masquerade (cached): %s -> %s", domain, cached);
|
|
+ vstring_truncate(addr, name_len + 1);
|
|
+ vstring_strcat(addr, cached);
|
|
+ return (1);
|
|
+ }
|
|
+ }
|
|
+
|
|
for (masqp = masq_domains->argv; (masq = *masqp) != 0; masqp++) {
|
|
for (truncate = 1; *masq == '!'; masq++)
|
|
truncate = !truncate;
|