#!/bin/bash -e
#
# set-dns-source.sh - Setup Source NAT in firewalld for outgoing DNS traffic
#
# Version 1.0, latest version, documentation and bugtracker available at:
#		https://gitlab.lindenaar.net/scripts/freeipa
#
# Copyright (c) 2018 Frederik Lindenaar
#
# This script is free software: you can redistribute and/or modify it under the
# terms of version 3 of the GNU General Public License as published by the Free
# Software Foundation, or (at your option) any later version of the license.
#
# This script is distributed in the hope that it will be useful but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, visit <http://www.gnu.org/licenses/> to download it.

case $1 in
  install)      CMD=add
                ;;
  remove)       CMD=remove
                ;;
  *)            echo "usage: $0 <install | remove>"
                exit 1
esac

IPV4ADDR=${IPV4ADDR:?Please provide an IPv4 address or set to 'none'}
IPV6ADDR=${IPV6ADDR:?Please provide an IPv6 address or set to 'none'}

DEV=${DEV:=$( /usr/sbin/ip route | fgrep ${IPV4ADDR:?No IPv4 address provided, please set device manually} | cut -d\  -f3 )}
: ${DEV:?No route found for $IPV4ADDR, please check config or set device manually}

# inspired by https://blog.sebastien.raveau.name/2009/04/per-process-routing.html
# and https://unix.stackexchange.com/questions/389756/how-to-use-snat-with-firewalld-vs-masq

for PROTO in ipv4 ipv6; do
  [ "$PROTO" == ipv6 ] && ADDR="$IPV6ADDR" || ADDR="$IPV4ADDR"
  if [ -n "$ADDR" -a "$ADDR" != none ]; then
    for MODE in "" --permanent; do
      firewall-cmd $MODE --direct --$CMD-rule $PROTO mangle OUTPUT 0 -m owner --uid-owner named -j MARK --set-mark 53
      firewall-cmd $MODE --direct --$CMD-rule $PROTO nat POSTROUTING 0 -o $DEV -m mark --mark 53 -j SNAT --to-source $ADDR
    done
  fi
done