Last active
December 31, 2023 18:52
-
-
Save u0m3/1c72c1dd27a812930d654d2ff144f8d9 to your computer and use it in GitHub Desktop.
Add/Change nftable rules when openvpn server starts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
## Add nft rules | |
# Target is something like: | |
# - nft insert iifname "enp2s0" oifname "tun0" ip saddr 192.168.22.0/24 ip daddr 192.168.2.0/24 counter accept | |
# - nft insert iifname "tun0" oifname "enp2s0" ip saddr 192.168.2.0/24 ip daddr 192.168.22.0/24 counter accept | |
# | |
# Documentation: | |
# - https://www.netfilter.org/projects/nftables/manpage.html | |
# - https://wiki.nftables.org/wiki-nftables/index.php/Main_Page | |
# - https://wiki.nftables.org/wiki-nftables/index.php/Simple_rule_management | |
# - https://wiki.nftables.org/wiki-nftables/index.php/Atomic_rule_replacement (this would have been nice if it were usable in my usecase) | |
# - https://wiki.nftables.org/wiki-nftables/index.php/Monitoring_ruleset_updates (this was fun: apparently replace does an add+delete) | |
# - https://wiki.nftables.org/wiki-nftables/index.php/Scripting (this might have been another way to go) | |
# - https://eklitzke.org/bash-$*-and-$@ | |
# - https://coderwall.com/p/85jnpq/bash-built-in-variables | |
# - https://stackoverflow.com/questions/59895/how-to-get-the-source-directory-of-a-bash-script-from-within-the-script-itself | |
# - https://www.oreilly.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html (for matching subnet) | |
# - https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/ | |
# - https://tomlee.co/2011/10/gnu-screen-splitting/ (for help with screen for tmux users) | |
## Variables | |
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" | |
LOGFILE="$SCRIPTDIR/server.up.sh.log" | |
REGEX_NET='\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}\b' | |
# TODO: try to make LAN dinamic too. | |
DEV_LAN="enp2s0" | |
NET_LAN="192.168.22.0/24" | |
DEV_VPN="" # keep empty to load dinamically from env variables passed by OpenVPN | |
NET_VPN="" # keep empty to load dinamically from env variables passed by OpenVPN | |
## Binaries | |
nft="/usr/sbin/nft" | |
ipcalc="/usr/bin/ipcalc" | |
grep="/usr/bin/grep" | |
( | |
# Test args and env | |
# echo '$#' $# ; echo '$@' "$@" ; echo "$( /usr/bin/env )" | |
## Variables check | |
if [ -z "$DEV_VPN" ]; then | |
DEV_VPN=$dev | |
fi | |
if [ -z "$NET_VPN" ]; then | |
NET_VPN=`$ipcalc "$ifconfig_local/$ifconfig_netmask" | grep Network | grep -iPo "$REGEX_NET"` | |
fi | |
echo 'DEV_LAN =' $DEV_LAN | |
echo 'NET_LAN =' $NET_LAN | |
echo 'DEV_VPN =' $DEV_VPN | |
echo 'NET_VPN =' $NET_VPN | |
RULE_DEV_VPN_TO_DEV_LAN="$($nft -a list chain ip filter FORWARD | $grep -P "iifname \"?$DEV_VPN\"?" | $grep -P "oifname \"?$DEV_LAN\"?")" | |
RULE_DEV_VPN_TO_DEV_LAN_RULE="iifname "$DEV_VPN" oifname "$DEV_LAN" ip saddr "$NET_VPN" ip daddr "$NET_LAN" counter accept" | |
echo 'RULE_DEV_VPN_TO_DEV_LAN =' $RULE_DEV_VPN_TO_DEV_LAN | |
echo 'RULE_DEV_VPN_TO_DEV_LAN_RULE =' $RULE_DEV_VPN_TO_DEV_LAN_RULE | |
if [ -z "$RULE_DEV_VPN_TO_DEV_LAN" ]; then | |
echo $nft insert rule ip filter FORWARD $RULE_DEV_VPN_TO_DEV_LAN_RULE | |
$nft insert rule ip filter FORWARD $RULE_DEV_VPN_TO_DEV_LAN_RULE | |
else | |
RULE_DEV_VPN_TO_DEV_LAN_SNET="$(echo $RULE_DEV_VPN_TO_DEV_LAN | $grep -Po "ip saddr \"?$REGEX_NET\"?" | $grep -Po "$REGEX_NET")" | |
RULE_DEV_VPN_TO_DEV_LAN_DNET="$(echo $RULE_DEV_VPN_TO_DEV_LAN | $grep -Po "ip daddr \"?$REGEX_NET\"?" | $grep -Po "$REGEX_NET")" | |
echo 'RULE_DEV_VPN_TO_DEV_LAN_SNET =' $RULE_DEV_VPN_TO_DEV_LAN_SNET | |
echo 'RULE_DEV_VPN_TO_DEV_LAN_DNET =' $RULE_DEV_VPN_TO_DEV_LAN_DNET | |
if [ "$RULE_DEV_VPN_TO_DEV_LAN_SNET" != "$NET_VPN" ] || [ "$RULE_DEV_VPN_TO_DEV_LAN_DNET" != "$NET_LAN" ]; then | |
RULE_DEV_VPN_TO_DEV_LAN_ID="$(echo $RULE_DEV_VPN_TO_DEV_LAN | $grep -Po '# handle \d+' | $grep -Po '\d+')" | |
echo 'RULE_DEV_VPN_TO_DEV_LAN_ID =' $RULE_DEV_VPN_TO_DEV_LAN_ID | |
echo $nft replace rule ip filter FORWARD handle $RULE_DEV_VPN_TO_DEV_LAN_ID $RULE_DEV_VPN_TO_DEV_LAN_RULE | |
$nft replace rule ip filter FORWARD handle $RULE_DEV_VPN_TO_DEV_LAN_ID $RULE_DEV_VPN_TO_DEV_LAN_RULE | |
fi | |
fi | |
RULE_DEV_LAN_TO_DEV_VPN="$($nft -a list chain ip filter FORWARD | $grep -P "iifname \"?$DEV_LAN\"?" | $grep -P "oifname \"?$DEV_VPN\"?")" | |
RULE_DEV_LAN_TO_DEV_VPN_RULE="iifname "$DEV_LAN" oifname "$DEV_VPN" ip saddr "$NET_LAN" ip daddr "$NET_VPN" counter accept" | |
echo 'RULE_DEV_LAN_TO_DEV_VPN =' $RULE_DEV_LAN_TO_DEV_VPN | |
echo 'RULE_DEV_LAN_TO_DEV_VPN_RULE =' $RULE_DEV_LAN_TO_DEV_VPN_RULE | |
if [ -z "$RULE_DEV_LAN_TO_DEV_VPN" ]; then | |
echo $nft insert rule ip filter FORWARD $RULE_DEV_LAN_TO_DEV_VPN_RULE | |
$nft insert rule ip filter FORWARD $RULE_DEV_LAN_TO_DEV_VPN_RULE | |
else | |
RULE_DEV_LAN_TO_DEV_VPN_SNET="$(echo $RULE_DEV_LAN_TO_DEV_VPN | $grep -Po "ip saddr \"?$REGEX_NET\"?" | $grep -Po "$REGEX_NET")" | |
RULE_DEV_LAN_TO_DEV_VPN_DNET="$(echo $RULE_DEV_LAN_TO_DEV_VPN | $grep -Po "ip daddr \"?$REGEX_NET\"?" | $grep -Po "$REGEX_NET")" | |
echo 'RULE_DEV_LAN_TO_DEV_VPN_SNET =' $RULE_DEV_LAN_TO_DEV_VPN_SNET | |
echo 'RULE_DEV_LAN_TO_DEV_VPN_DNET =' $RULE_DEV_LAN_TO_DEV_VPN_DNET | |
if [ "$RULE_DEV_LAN_TO_DEV_VPN_SNET" != "$NET_LAN" ] || [ "$RULE_DEV_LAN_TO_DEV_VPN_DNET" != "$NET_VPN" ]; then | |
RULE_DEV_LAN_TO_DEV_VPN_ID="$(echo $RULE_DEV_LAN_TO_DEV_VPN | $grep -Po '# handle \d+' | $grep -Po '\d+')" | |
echo 'RULE_DEV_LAN_TO_DEV_VPN_ID =' $RULE_DEV_LAN_TO_DEV_VPN_ID | |
echo $nft replace rule ip filter FORWARD handle $RULE_DEV_LAN_TO_DEV_VPN_ID $RULE_DEV_LAN_TO_DEV_VPN_RULE | |
$nft replace rule ip filter FORWARD handle $RULE_DEV_LAN_TO_DEV_VPN_ID $RULE_DEV_LAN_TO_DEV_VPN_RULE | |
fi | |
fi | |
) | tee $LOGFILE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment