Compare commits

..

1 Commits

Author SHA1 Message Date
missytake
cf934b966a echobot: require dovecot to be running 2025-12-01 10:31:54 +01:00
7 changed files with 35 additions and 118 deletions

View File

@@ -11,9 +11,6 @@
- Organized cmdeploy into install, configure, and activate stages - Organized cmdeploy into install, configure, and activate stages
([#695](https://github.com/chatmail/relay/pull/695)) ([#695](https://github.com/chatmail/relay/pull/695))
- echobot: print invite-link also if it's deployed locally
([#751](https://github.com/chatmail/relay/pull/751))
- docs: move readme.md docs to sphinx documentation rendered at https://chatmail.at/doc/relay - docs: move readme.md docs to sphinx documentation rendered at https://chatmail.at/doc/relay
([#711](https://github.com/chatmail/relay/pull/711)) ([#711](https://github.com/chatmail/relay/pull/711))

View File

@@ -11,7 +11,6 @@ import pathlib
import shutil import shutil
import subprocess import subprocess
import sys import sys
import time
from pathlib import Path from pathlib import Path
import pyinfra import pyinfra
@@ -110,20 +109,13 @@ def run_cmd(args, out):
try: try:
retcode = out.check_call(cmd, env=env) retcode = out.check_call(cmd, env=env)
if retcode == 0: if retcode == 0:
if not args.disable_mail and not args.dry_run: if not args.disable_mail:
print("\nYou can try out the relay by talking to this echo bot: ") print("\nYou can try out the relay by talking to this echo bot: ")
invite_path = Path("/var/lib/echobot/invite-link.txt") sshexec = SSHExec(args.config.mail_domain, verbose=args.verbose)
if ssh_host in ["localhost", "@local", "@docker"]:
while not invite_path.exists():
time.sleep(0.1)
with invite_path.open() as f:
print(f.readline())
else:
echo_sshexec = get_sshexec(ssh_host, verbose=args.verbose)
print( print(
echo_sshexec( sshexec(
call=remote.rshell.shell, call=remote.rshell.shell,
kwargs=dict(command=f"cat {invite_path}"), kwargs=dict(command="cat /var/lib/echobot/invite-link.txt"),
) )
) )
out.green("Deploy completed, call `cmdeploy dns` next.") out.green("Deploy completed, call `cmdeploy dns` next.")

View File

@@ -9,7 +9,6 @@ if nsigs == nil then
return nil return nil
end end
local valid = false
for i = 1, nsigs do for i = 1, nsigs do
sig = odkim.get_sighandle(ctx, i - 1) sig = odkim.get_sighandle(ctx, i - 1)
sigres = odkim.sig_result(sig) sigres = odkim.sig_result(sig)
@@ -20,19 +19,10 @@ for i = 1, nsigs do
-- Any valid signature that was not ignored like this -- Any valid signature that was not ignored like this
-- means the message is acceptable. -- means the message is acceptable.
if sigres == 0 then if sigres == 0 then
valid = true return nil
end end
end end
if valid then odkim.set_reply(ctx, "554", "5.7.1", "No valid DKIM signature found")
-- Strip all DKIM-Signature headers after successful validation odkim.set_result(ctx, SMFIS_REJECT)
-- Delete in reverse order to avoid index shifting.
for i = nsigs, 1, -1 do
odkim.del_header(ctx, "DKIM-Signature", i)
end
else
odkim.set_reply(ctx, "554", "5.7.1", "No valid DKIM signature found")
odkim.set_result(ctx, SMFIS_REJECT)
end
return nil return nil

View File

@@ -1,5 +1,6 @@
[Unit] [Unit]
Description=Chatmail echo bot for testing it works Description=Chatmail echo bot for testing it works
Requires=dovecot.service
[Service] [Service]
ExecStart={execpath} {config_path} ExecStart={execpath} {config_path}

View File

@@ -140,34 +140,34 @@ def main():
config.webdev = True config.webdev = True
assert config.mail_domain assert config.mail_domain
# start web page generation, open a browser and wait for changes
www_path, src_path, build_dir = get_paths(config) www_path, src_path, build_dir = get_paths(config)
build_dir = build_webpages(src_path, build_dir, config) build_dir = build_webpages(src_path, build_dir, config)
index_path = build_dir.joinpath("index.html") index_path = build_dir.joinpath("index.html")
webbrowser.open(str(index_path)) webbrowser.open(str(index_path))
print(f"\nOpened URL: file://{index_path.resolve()}\n")
print(f"Watching {src_path} directory for changes...")
stats = snapshot_dir_stats(src_path) stats = snapshot_dir_stats(src_path)
print(f"\nOpened URL: file://{index_path.resolve()}\n")
print(f"watching {src_path} directory for changes")
changenum = 0 changenum = 0
debounce_time = 0.5 # wait 0.5s after detecting a change count = 0
while True: while True:
time.sleep(1)
newstats = snapshot_dir_stats(src_path) newstats = snapshot_dir_stats(src_path)
if newstats == stats and count % 60 != 0:
count += 1
time.sleep(1.0)
continue
if newstats != stats: for key in newstats:
changed_files = [f for f in newstats if stats.get(f) != newstats[f]] if stats[key] != newstats[key]:
for f in changed_files: print(f"*** CHANGED: {key}")
print(f"*** CHANGED: {f}") changenum += 1
stats = newstats stats = newstats
changenum += 1
build_webpages(src_path, build_dir, config) build_webpages(src_path, build_dir, config)
print(f"[{changenum}] regenerated web pages at: {index_path}") print(f"[{changenum}] regenerated web pages at: {index_path}")
print(f"URL: file://{index_path.resolve()}\n\n") print(f"URL: file://{index_path.resolve()}\n\n")
count = 0
time.sleep(debounce_time) # simple debounce
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -273,11 +273,9 @@ Incoming emails must have a valid DKIM signature with
Signing Domain Identifier (SDID, ``d=`` parameter in the DKIM-Signature Signing Domain Identifier (SDID, ``d=`` parameter in the DKIM-Signature
header) equal to the ``From:`` header domain. This property is checked header) equal to the ``From:`` header domain. This property is checked
by OpenDKIM screen policy script before validating the signatures. This by OpenDKIM screen policy script before validating the signatures. This
corresponds to strict :rfc:`DMARC <7489>` alignment (``adkim=s``). correpsonds to strict :rfc:`DMARC <7489>` alignment (``adkim=s``).
If there is no valid DKIM signature on the incoming email, the If there is no valid DKIM signature on the incoming email, the
sender receives a “5.7.1 No valid DKIM signature found” error. sender receives a “5.7.1 No valid DKIM signature found” error.
After validating the DKIM signature,
the `final.lua` script strips all ``OpenDKIM:`` headers to reduce message size on disc.
Note that chatmail relays Note that chatmail relays

View File

@@ -22,12 +22,7 @@ Note that your chatmail relay still needs to be able to make outgoing
connections on port 25 to send messages outside. connections on port 25 to send messages outside.
To setup a reverse proxy (or rather Destination NAT, DNAT) for your To setup a reverse proxy (or rather Destination NAT, DNAT) for your
chatmail relay, follow these instructions: chatmail relay, put the following configuration in
Linux
^^^^^
Put the following configuration in
``/etc/nftables.conf``: ``/etc/nftables.conf``:
:: ::
@@ -115,61 +110,5 @@ Uncomment in ``/etc/sysctl.conf`` the following two lines:
Then reboot the relay or do ``sysctl -p`` and Then reboot the relay or do ``sysctl -p`` and
``nft -f /etc/nftables.conf``. ``nft -f /etc/nftables.conf``.
FreeBSD / pf
^^^^^^^^^^^^
Put the following configuration in
``/etc/pf.conf``:
::
ext_if = "em0"
forward_ports = "{ 25, 80, 143, 443, 465, 587, 993 }"
chatmail_ipv4 = "AAA.BBB.CCC.DDD"
icmp_types = "{ echoreq, echorep, unreach, timex }"
chatmail_ipv6 = "XXX::1"
icmp6_types = "{ echorep, echoreq, neighbradv, neighbrsol, routeradv, routersol, unreach, toobig, timex }"
set skip on lo0
nat on $ext_if inet from any to any -> ($ext_if:0)
nat on $ext_if inet6 from any to any -> ($ext_if:0)
# Define the redirect rules
rdr on $ext_if inet proto tcp from any to ($ext_if:0) port $forward_ports -> $chatmail_ipv4
rdr on $ext_if inet6 proto tcp from any to ($ext_if:0) port $forward_ports -> $chatmail_ipv6
# Accept the incoming traffic to the specified ports we will NAT redirect
pass in quick on $ext_if inet proto tcp from any to any port $forward_ports flags S/SA modulate state
pass in quick on $ext_if inet6 proto tcp from any to any port $forward_ports flags S/SA modulate state
# Allow incoming SSH for host mgmt
pass in quick on $ext_if proto tcp from any to ($ext_if) port 22 flags S/SA modulate state
# Allow ICMP
pass in quick on $ext_if inet proto icmp all icmp-type $icmp_types keep state
pass in quick on $ext_if inet6 proto ipv6-icmp all icmp6-type $icmp6_types keep state
# Allow traffic from anyone to go through the NAT
pass on $ext_if inet proto tcp from any to $chatmail_ipv4 flags S/SA modulate state
pass on $ext_if inet6 proto tcp from any to $chatmail_ipv6 flags S/SA modulate state
# Default allow out
pass out quick on $ext_if from any to any
# Default block
block drop in log all
Insert into ``/etc/sysctl.conf.local`` the following two lines:
::
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
Activate the sysctls with ``service sysctl onestart``.
Enable the pf firewall with ``service pf enable``.
Apply the firewall rules with ``service pf start`` or ``pfctl -f /etc/pf.conf``.
Note, enabling the firewall may interrupt your SSH session, but you can reconnect.
Once proxy relay is set up, you can add its IP address to the DNS. Once proxy relay is set up, you can add its IP address to the DNS.