Protecting GWIA SMTP Services

A firewalld + ipsets solution


✅ Project Summary: Protecting GWIA SMTP Services Using firewalld + ipsets

🎯 Objective

Protect GroupWise GWIA SMTP ports (e.g. 192.168.10.249:2525) from unwanted SMTP access by dynamically allowing only:

  • Legitimate mail relay providers (e.g. Dynu Mail Relay)

  • Internal subnets for testing/monitoring

  • Drop all other connections at the firewall level, not at the mail server

This solution requires the external router to preserve the source IP address (via full NAT or DMZ with NAT reflection/hairpin), so that firewall rules can match public sender IPs.


📌 Topology Example

[Dynu SMTP Relay IPs] ──> [Public IP Router (NAT 1:1)] ──> [GWIA Host: 192.168.10.249:2525]
                               |
                               +-- Port-forward (WAN 25 → LAN 2525)

📦 Requirements

  • OpenSUSE Leap 15.6 or compatible Linux

  • firewalld (with support for rich rules and ipset)

  • Scripted dynamic config (gwiaprotection.sh)

  • DNS access to resolve MX records

  • Assumption: router allows original source IP to reach firewall


🧰 Dynamic IP Filtering Strategy

  • Perform DNS MX lookup for your mail domains (e.g. eacbelcher.net)

  • Resolve Dynu’s outbound relays (e.g. mx1.dynu.com, etc.)

  • Resolve A/AAAA records for those MX hosts

  • Add the resulting IPs into an ipset

  • Create rich firewall rules allowing only those IPs on specified ports


🛠️ Installation & Setup

1. 🧪 Ensure firewalld is enabled

sudo systemctl enable firewalld
sudo systemctl start firewalld
sudo firewall-cmd --state

2. 📁 Script Location

Place the script here:

/etc/scripts/gwiaprotection.sh

Make executable:

chmod +x /etc/scripts/gwiaprotection.sh

🔐 Sample Invocation

sudo /etc/scripts/gwiaprotection.sh --ip 192.168.10.249 --domain eacbelcher.net --port 2525 --config

Output Example:

[DEBUG] do_config: remove_rules
[DEBUG] do_config: ensure_ipsets
[DEBUG] do_config: populate_ipsets
[DEBUG] do_config: add_rules
[gwiaprotection] Configured 192.168.10.249 for domains: eacbelcher.net on ports: 2525

📄 Rich Firewall Rule Structure

Generated rules (via firewall-cmd) include:

rule priority="-200" family="ipv4" source ipset="gwp_192_168_10_249_v4" destination address="192.168.10.249" port port="2525" protocol="tcp" accept
rule priority="100" family="ipv4" destination address="192.168.10.249" port port="2525" protocol="tcp" drop
rule priority="-200" family="ipv4" source address="192.168.10.0/24" destination address="192.168.10.249" port port="2525" protocol="tcp" accept

✅ Allows:

  • Dynu source IPs (via ipset)

  • Internal subnet
    🚫 Denies:

  • All others


🔄 Script Workflow (Simplified)

1. Remove existing firewall rules
2. Create or verify ipsets (v4 and v6)
3. Lookup MX records for domain(s)
4. Resolve A/AAAA for each MX
5. Populate ipsets with resolved IPs
6. Add rich rules to allow those IPs on the target port
7. Add fallback drop rule
8. Reload firewalld

🧪 Test & Debug

✅ Check IPSet Contents

sudo ipset list gwp_192_168_10_249_v4

Should list resolved Dynu IPs:

Members:
162.216.242.35
162.216.242.36
...

✅ Show Rich Rules

sudo firewall-cmd --permanent --zone=public --list-rich-rules

✅ Simulate Connection from External IP

From a public host:

telnet mail.ezeasproducts.com.au 25

✅ Monitor in Real Time

sudo tcpdump -i any -nn dst host 192.168.10.249 and dst port 2525

Expected:

  • Allowed IPs: connection established

  • Others: dropped with no response


🔁 To Undo / Reset

sudo /etc/scripts/gwiaprotection.sh --ip 192.168.10.249 --reset

Or manually:

sudo firewall-cmd --permanent --zone=public \
  --remove-rich-rule='rule family="ipv4" source ipset="gwp_192_168_10_249_v4" destination address="192.168.10.249" port port="2525" protocol="tcp" accept'

sudo firewall-cmd --permanent --delete-ipset=gw_192_168_10_249_v4
sudo firewall-cmd --reload

📤 Dynu Reference IP Ranges

If you prefer to use static IPs:

162.216.242.0/24
142.202.188.16/29
107.161.27.201
2602:ff23:0:8888::/64

But ideally, resolve from MX records for resilience.


🧾 Summary

Feature Value
Protection Layer firewalld + ipsets (L3/L4)
Mail Server GroupWise GWIA
Relay Provider Dynu
Allowed IPs Source Dynamic from MX + A/AAAA resolution
Script Location /etc/scripts/gwiaprotection.sh
Config Type Rich rules + ipsets
Router Requirement Full NAT with original source IP retained


gwiaprotection.sh

copy this file to server hosting GWIA services.
# gwiaprotection.sh
# Lock down a specific GWIA IP:PORT(S) so only MX hosts (plus internal nets/extra IPs) can connect.
# Usage:
#   /etc/scripts/gwiaprotection.sh --ip 192.168.10.250 --config
#   /etc/scripts/gwiaprotection.sh --ip 192.168.10.250 --status
#   /etc/scripts/gwiaprotection.sh --ip 192.168.10.250 --clear
#
# Loads config from /etc/scripts/gwiaprotection.<A.B.C.D>.conf (derived from --ip)
# Config keys:
#   GWIA_PORTS="2525 25"
#   DOMAINS=("eacbelcher.net")
#   INTERNAL_NETS="192.168.10.0/24"
#   EXTRA_IPS_V4=""
#   EXTRA_IPS_V6=""