Catch and forward traffic destined for specific host. Multiple destinations

This example for two destinations (could be more)

Install socat

apt install socat

Add iptables rules to firewalld (works only with IP – replace hostname with associated IP)

firewall-cmd --permanent --direct --add-rule ipv4 nat OUTPUT 0 -p tcp -d redcap.vumc.org --dport 443 -j REDIRECT --to-ports 12345
firewall-cmd --permanent --direct --add-rule ipv4 nat OUTPUT 0 -p tcp -d api.twilio.com --dport 443 -j REDIRECT --to-ports 12346
firewall-cmd --reload

check results

firewall-cmd --direct --get-all-rules

create systemd template

touch /etc/systemd/system/socat@.service

content of template

[Unit]
Description=Socat tunnel for port %i
After=network.target

[Service]
ExecStart=
ExecStart=/usr/bin/socat TCP4-LISTEN=%i,fork,reuseaddr PROXY:your_proxy.ca:example.com:443,proxyport=3128
Restart=always
RestartSec=3
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

We’ll override example.com per instance using systemctl edit.

systemctl edit socat@12345

content of socat@12345

[Service]
ExecStart=
ExecStart=/usr/bin/socat TCP4-LISTEN:12345,fork,reuseaddr PROXY:your_proxy.ca:redcap.vumc.org:443,proxyport=3128

another

systemctl edit socat@12346

content of socat@12346

[Service]
ExecStart=
ExecStart=/usr/bin/socat TCP4-LISTEN:12346,fork,reuseaddr PROXY:your_proxy.ca:api.twilio.com:443,proxyport=3128

start and enable both services

systemctl daemon-reload
systemctl enable --now socat@12345
systemctl enable --now socat@12346

check service status

systemctl status socat@12345
systemctl status socat@12346

done.

Little extra: Script example to update dynamically changed IP for hostnames

#!/bin/bash

LOGFILE="/var/log/redcap_firewall_update.log"
MIN_PORT=12345
MAX_PORT=12351
DPORT=443   # destination port to match on (e.g., HTTPS)

# List of "hostname redirect_port"
HOSTS_AND_PORTS=(
  "redcap.vumc.org 12345"
  "api.twilio.com 12346"
  "api.mosio.com 12347"
  "api.sendgrid.com 12348"
  "www.redcap-cats.org 12349"
  "redcap.link 12350"
  "cde.nlm.nih.gov 12351"
)

# Ensure the log file exists and is writable
touch "$LOGFILE" || { echo "Error: Cannot write to $LOGFILE"; exit 1; }

{
  echo "[$(date)] --- Starting firewall rule cleanup and insertion ---"
  echo ""

  # Get all permanent direct rules
  rules=$(firewall-cmd --permanent --direct --get-all-rules)

  # Loop through each rule and remove those within the port range
  while IFS= read -r rule; do
    to_port=$(echo "$rule" | grep -oP -- '--to-ports\s+\K[0-9]+')
    if [[ -n "$to_port" && "$to_port" -ge "$MIN_PORT" && "$to_port" -le "$MAX_PORT" ]]; then
      echo "Removing rule: $rule"
      firewall-cmd --permanent --direct --remove-rule $rule
    fi
  done <<< "$rules"

  echo "Reloading firewall after cleanup..."
  firewall-cmd --reload

  echo ""
  echo "Inserting updated rules..."

  # Add new rules
  for entry in "${HOSTS_AND_PORTS[@]}"; do
    HOSTNAME=$(echo "$entry" | awk '{print $1}')
    REDIRECT_PORT=$(echo "$entry" | awk '{print $2}')
    echo ""
    echo "Resolving $HOSTNAME..."
    echo ""
    IPV4S=$(dig +short "$HOSTNAME" | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}')

    for IP in $IPV4S; do
      echo "Adding rule: $IP -> $REDIRECT_PORT"
      firewall-cmd --permanent --direct --add-rule ipv4 nat OUTPUT 0 -p tcp -d "$IP" --dport $DPORT -j REDIRECT --to-ports $REDIRECT_PORT
    done
  done

  echo "Reloading firewall after insertion..."
  firewall-cmd --reload

  echo ""
  echo "[$(date)] --- Firewall update complete ---"
  echo ""
} >> "$LOGFILE" 2>&1

Schedule it in crontab

0 */4 * * * /bin/bash /opt/update_redcap_firewall.sh

be happy!