114 lines
2.8 KiB
Python
Executable File
114 lines
2.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import socket
|
|
import sys
|
|
|
|
SRS_DOMAIN = "srs.warenform.de"
|
|
SOCKET_HOST = "127.0.0.1"
|
|
SOCKET_PORT = 10003
|
|
TIMEOUT = 5
|
|
MAX_RESPONSE = 4096
|
|
|
|
|
|
def read_netstring(sock):
|
|
length_bytes = bytearray()
|
|
|
|
while True:
|
|
char = sock.recv(1)
|
|
if not char:
|
|
raise ValueError("Incomplete netstring length")
|
|
if char == b":":
|
|
break
|
|
if char < b"0" or char > b"9" or len(length_bytes) >= 8:
|
|
raise ValueError("Invalid netstring length")
|
|
length_bytes.extend(char)
|
|
|
|
if not length_bytes:
|
|
raise ValueError("Empty netstring length")
|
|
|
|
length = int(length_bytes)
|
|
|
|
if length > MAX_RESPONSE:
|
|
raise ValueError("Netstring response too large")
|
|
|
|
data = bytearray()
|
|
|
|
while len(data) < length + 1:
|
|
chunk = sock.recv(length + 1 - len(data))
|
|
if not chunk:
|
|
raise ValueError("Incomplete netstring response")
|
|
data.extend(chunk)
|
|
|
|
if data[-1:] != b",":
|
|
raise ValueError("Invalid netstring terminator")
|
|
|
|
return bytes(data[:-1]).decode("utf-8")
|
|
|
|
|
|
def verify_srs(address):
|
|
request = f"reverse {address}".encode("utf-8")
|
|
packet = str(len(request)).encode("ascii") + b":" + request + b","
|
|
|
|
with socket.create_connection(
|
|
(SOCKET_HOST, SOCKET_PORT), timeout=TIMEOUT
|
|
) as sock:
|
|
sock.settimeout(TIMEOUT)
|
|
sock.sendall(packet)
|
|
response = read_netstring(sock)
|
|
|
|
if response.startswith("OK "):
|
|
original = response[3:]
|
|
if not original or "@" not in original:
|
|
raise ValueError("Invalid reverse result")
|
|
return "OK"
|
|
|
|
if response.startswith("NOTFOUND "):
|
|
return "REJECT 550 5.1.1 Invalid SRS address"
|
|
|
|
raise ValueError(f"Unexpected socketmap response: {response}")
|
|
|
|
|
|
def check_recipient(recipient):
|
|
if "@" not in recipient:
|
|
return "DUNNO"
|
|
|
|
localpart, domain = recipient.rsplit("@", 1)
|
|
|
|
if domain.lower() != SRS_DOMAIN:
|
|
return "DUNNO"
|
|
|
|
if not localpart.upper().startswith(("SRS0=", "SRS1=")):
|
|
return "REJECT 550 5.1.1 Invalid SRS address"
|
|
|
|
try:
|
|
return verify_srs(recipient)
|
|
except (OSError, UnicodeError, ValueError) as exc:
|
|
print(f"SRS verification error: {exc}", file=sys.stderr)
|
|
return "DEFER 451 4.3.0 SRS verification unavailable"
|
|
|
|
|
|
def main():
|
|
while True:
|
|
attributes = {}
|
|
|
|
for line in sys.stdin:
|
|
line = line.rstrip("\r\n")
|
|
|
|
if not line:
|
|
break
|
|
|
|
if "=" in line:
|
|
key, value = line.split("=", 1)
|
|
attributes[key] = value
|
|
else:
|
|
return
|
|
|
|
recipient = attributes.get("recipient", "")
|
|
action = check_recipient(recipient)
|
|
|
|
print(f"action={action}\n", flush=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|