Postfix header_checks с многострочными заголовками и группой захвата

Postfix header_checks с многострочными заголовками и группой захвата

У нас есть регулярное выражение header_checks, переданное процессу «очистки», но оно не обрабатывает заголовок как единый заголовок, если он находится в нескольких строках.

header_check (передача значения заголовка в FILTER):

/^X-OurHeader:\s+(.*?)/ FILTER $1

мастер.cf:

cleanup_service.        unix  n       -       y       -       0       cleanup
  -o header_checks=regexp:/etc/postfix/header_check

Пример многострочного заголовка, где происходит сбой:

X-OurHeader: a_special_filter_command:my.sub.domain
 b.mail.whatever.com

Исходный полный заголовок до разбиения на несколько строк выглядит так:

X-OurHeader: a_special_filter_command:my.sub.domainb.mail.whatever.com

Результат, переданный в FILTER, будет следующим: a_special_filter_command:my.sub.domain и отсутствует оставшееся имя хоста во второй строке b.mailwhatever.com.

Если я изменю header_check на это, то он будет захватывать следующую строку:

/^X-OurHeader:\s+([\s\S]*)/ FILTER $1

Группа захвата $1 затем содержит вторую строку, но в захваченном тексте все еще есть пробел (и, предположительно, новая строка), так что это не работает. Это выглядит так:

X-OurHeader: a_special_filter_command:my.sub.domain b.mail.whatever.com

Просматривая логи при первом подходе, мы видим

postfix/cleanup[123456]: 27429A1FE8: filter: header X-OurHeader: a_special_filter_command:my.sub.domain? b.mail.whatever.com

Есть ли альтернативный подход, который кто-нибудь мог бы предложить? Конечная цель заключается в том, что мы помечаем заголовок специальными значениями cmd:hostname, которые необходимо отправить в FILTER, но хотим поддержать разбиение значения hdr на несколько строк для длинного заголовка, чтобы соответствовать стандарту «длина ДОЛЖНА быть < 78».

решение1

Если вы знаете или можете гарантировать, что существует только определенное количество вариаций, добавьте дополнительные выражения, чтобы отлавливать их по отдельности /..:(.*) (.*)$/ -> /..:$1$2/— постфикс продолжит со следующего выражения, если пробела нет, поэтому сохраняйте простоту шаблонов, помещая сложное совпадение первым.


Если нет, но все еще в пределах возможностей регулярных выражений, возможно, есть способцепочка множественных поисков. Я не могу собрать все воедино, но если это доступно в вашем дистрибутиве и вообще работает, документация должна быть полезна, начните с руководства header_checksи DATABASE_READMEфайла.

pipemap:{pcre:/extract/category.pcre,pcre:/map/category/to/filter/command.pcre}

Основная идея: сначала получите общее направление (например, MYFILTER: $1), и только затем вносите необходимые изменения, чтобы сделать его допустимой постфиксной командой, тщательно следя за тем, чтобы все входные данные приводили к допустимому выводу ( MYFILTER: (valid1|valid2) -> FILTER host:portплюс резервная строка MYFILTER:-> FILTER: default:port).


Если это не удается, то обычно, когда вам нужно сделать что-то слишком мощное для регулярных выражений и header_checks, вы переходите к полноте по Тьюрингу:

  1. Достаточно динамичный поиск. Например, если вам нравится SQL, это должно дать вам что-то не настолько менее читаемое/поддерживаемое. Остерегайтесь непреднамеренных логических результатов от множественных поисковheader_checks = sqlite:/path/to/definition.conf pcre:/remaining/simpler/rules.pcre

  2. Демон milter/policy. Они могут даже вызывать внешние двоичные файлы, вообще не перенаправляя сообщение. В зависимости от интерфейса вашей текущей идеи следующего FILTER в очереди, это может быть более или менее удобно.


Я также считаю, что есть способы заставить постфикс работать правильнотранспортданное сообщение через несколько экземпляров header_checks, если это необходимо, но я бы не рекомендовал этот маршрут, он не очень хорошо сочетается с другими (более или менее динамичными) решениями по маршрутизации.

Связанный контент