improve conditions handling

This commit is contained in:
2021-09-14 01:36:32 +02:00
parent ef025d758c
commit e34e85af6b
4 changed files with 70 additions and 77 deletions

View File

@@ -199,6 +199,33 @@ class ModifyMilter(Milter.Base):
self.logger.debug(
f"accepted milter connection from {self.IP} "
f"port {self.port}")
# pre-filter rules and actions by the host condition
# also check if the mail body is needed by any upcoming action.
self.rules = []
self._headersonly = True
for rule in ModifyMilter._rules:
if rule.conditions is None or \
rule.conditions.match_host(self.IP):
actions = []
for action in rule.actions:
if action.conditions is None or \
action.conditions.match_host(self.IP):
actions.append(action)
if not action.headersonly():
self._headersonly = False
if actions:
# copy needed rules to preserve configured actions
rule = copy(rule)
rule.actions = actions
self.rules.append(rule)
if not self.rules:
self.logger.debug(
"host is ignored by all rules, skip further processing")
return Milter.ACCEPT
except Exception as e:
self.logger.exception(
f"an exception occured in connect method: {e}")
@@ -244,37 +271,6 @@ class ModifyMilter(Milter.Base):
self.logger = CustomLogger(
self.logger, {"qid": self.qid, "name": "milter"})
self.logger.debug("received queue-id from MTA")
# pre-filter rules and actions by the host condition, other
# conditions (headers, envelope-from, envelope-to) may get
# changed by executed actions later on.
# also check if the mail body is needed by any upcoming action.
self.rules = []
self._headersonly = True
for rule in ModifyMilter._rules:
if rule.conditions is None or \
rule.conditions.match(host=self.IP, qid=self.qid):
actions = []
for action in rule.actions:
if action.conditions is None or \
action.conditions.match(host=self.IP,
qid=self.qid):
actions.append(action)
if not action.headersonly():
self._headersonly = False
if actions:
# copy needed rules to preserve configured actions
rule = copy(rule)
rule.actions = actions
self.rules.append(rule)
if not self.rules:
self.logger.debug(
"message is ignored by all rules, skip further processing")
return Milter.ACCEPT
self.fp = BytesIO()
except Exception as e:
self.logger.exception(
@@ -341,7 +337,7 @@ class ModifyMilter(Milter.Base):
refold_source='none'))
self.msginfo = {
"mailfrom": self.mailfrom,
"rcpts": self.rcpts,
"rcpts": [*self.rcpts],
"vars": {}}
self._replacebody = False
@@ -356,7 +352,7 @@ class ModifyMilter(Milter.Base):
if self._replacebody:
data = self.msg.as_bytes()
body_pos = data.find(b"\r\n\r\n") + 4
self.logger.debug("replacebody")
self.logger.debug("replace body")
super().replacebody(data[body_pos:])
del data

View File

@@ -194,9 +194,6 @@ class Action:
logger = CustomLogger(
self.logger, {"qid": milter.qid, "name": self._name})
if self.conditions is None or \
self.conditions.match(envfrom=milter.mailfrom,
envto=[*milter.rcpts],
headers=milter.msg.items(),
qid=milter.qid):
self.conditions.match(milter):
return self._class.execute(
milter=milter, pretend=self.pretend, logger=logger)

View File

@@ -81,15 +81,10 @@ class Conditions:
self._args = cfg["args"]
self.logger = cfg.logger
def match(self, host=None, envfrom=None, envto=None, headers=None,
qid=None):
if qid is None:
logger = self.logger
else:
def match_host(self, host):
logger = CustomLogger(
self.logger, {"qid": qid, "name": self._name})
self.logger, {"name": self._name})
if host:
ip = IPAddress(host)
if "local" in self._args:
@@ -124,6 +119,13 @@ class Conditions:
logger.debug(
f"condition hosts matches for host {host}")
return True
def match(self, milter):
logger = CustomLogger(
self.logger, {"qid": milter.qid, "name": self._name})
envfrom = milter.msginfo["mailfrom"]
if envfrom and "envfrom" in self._args:
if not self._args["envfrom"].match(envfrom):
logger.debug(
@@ -135,6 +137,7 @@ class Conditions:
f"condition envfrom matches for "
f"envelope-from address {envfrom}")
envto = milter.msginfo["rcpts"]
if envto and "envto" in self._args:
if not isinstance(envto, list):
envto = [envto]
@@ -150,9 +153,9 @@ class Conditions:
f"condition envto matches for "
f"envelope-to address {envto}")
if headers and "header" in self._args:
if "header" in self._args:
match = None
for field, value in headers:
for field, value in milter.msg.items():
header = f"{field}: {value}"
match = self._args["header"].search(header)
if match:

View File

@@ -86,10 +86,7 @@ class Rule:
def execute(self, milter):
"""Execute all actions of this rule."""
if self.conditions is None or \
self.conditions.match(envfrom=milter.mailfrom,
envto=[*milter.rcpts],
headers=milter.msg.items(),
qid=milter.qid):
self.conditions.match(milter):
for action in self.actions:
milter_action = action.execute(milter)
if milter_action is not None: