2020-02-01 15:58:02 +00:00
#!/bin/sh
2020-04-14 11:52:29 +02:00
#
2022-02-16 23:28:09 -07:00
# Copyright (c) 2018-2022, Christer Edwards <christer.edwards@gmail.com>
2021-01-09 15:42:24 -07:00
# All rights reserved.
#
2020-02-01 15:58:02 +00:00
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
2020-04-14 11:52:29 +02:00
#
2020-02-01 15:58:02 +00:00
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
2020-04-14 11:52:29 +02:00
#
2020-02-01 15:58:02 +00:00
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
2020-04-14 11:52:29 +02:00
#
2020-02-01 15:58:02 +00:00
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
2020-04-14 11:52:29 +02:00
#
2020-02-01 15:58:02 +00:00
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2020-08-30 10:57:14 -04:00
. /usr/local/share/bastille/common.sh
2020-02-01 15:58:02 +00:00
. /usr/local/etc/bastille/bastille.conf
usage( ) {
2022-03-01 21:54:03 -05:00
error_exit "Usage: bastille rdr TARGET [clear|list|(tcp|udp host_port jail_port [log ['(' logopts ')'] ] )]"
2020-02-01 15:58:02 +00:00
}
# Handle special-case commands first.
case " $1 " in
help| -h| --help)
usage
; ;
esac
if [ $# -lt 2 ] ; then
usage
fi
2023-03-16 20:58:11 +01:00
bastille_root_check
2020-02-01 15:58:02 +00:00
TARGET = " ${ 1 } "
2021-09-02 22:44:49 +02:00
JAIL_NAME = ""
JAIL_IP = ""
2023-03-28 15:03:53 +02:00
JAIL_IP6 = ""
2021-09-02 22:44:49 +02:00
EXT_IF = ""
2020-02-01 15:58:02 +00:00
shift
2021-09-02 22:44:49 +02:00
check_jail_validity( ) {
# Can only redirect to single jail
if [ " ${ TARGET } " = 'ALL' ] ; then
error_exit "Can only redirect to a single jail."
fi
2020-02-01 15:58:02 +00:00
2021-09-02 22:44:49 +02:00
# Check if jail name is valid
2021-12-17 19:09:49 -07:00
JAIL_NAME = $( /usr/sbin/jls -j " ${ TARGET } " name 2>/dev/null)
2021-09-02 22:44:49 +02:00
if [ -z " ${ JAIL_NAME } " ] ; then
error_exit " Jail not found: ${ TARGET } "
fi
2020-02-01 15:58:02 +00:00
2021-09-02 22:44:49 +02:00
# Check if jail ip4 address (ip4.addr) is valid (non-VNET only)
if [ " $( bastille config $TARGET get vnet) " != 'enabled' ] ; then
2021-12-17 19:09:49 -07:00
JAIL_IP = $( /usr/sbin/jls -j " ${ TARGET } " ip4.addr 2>/dev/null)
2021-09-02 22:44:49 +02:00
if [ -z " ${ JAIL_IP } " -o " ${ JAIL_IP } " = "-" ] ; then
error_exit " Jail IP not found: ${ TARGET } "
fi
2021-01-01 09:23:26 -07:00
fi
2023-03-28 15:03:53 +02:00
# Check if jail ip6 address (ip6.addr) is valid (non-VNET only)
if [ " $( bastille config $TARGET get vnet) " != 'enabled' ] ; then
2023-06-21 20:34:19 -06:00
if [ " $( bastille config $TARGET get ip6) " != 'disabled' ] && [ " $( bastille config $TARGET get ip6) " != 'not set' ] ; then
JAIL_IP6 = $( /usr/sbin/jls -j " ${ TARGET } " ip6.addr 2>/dev/null)
fi
2023-03-28 15:03:53 +02:00
fi
2020-02-01 15:58:02 +00:00
2023-06-21 20:34:19 -06:00
2021-09-02 22:44:49 +02:00
# Check if rdr-anchor is defined in pf.conf
if ! ( pfctl -sn | grep rdr-anchor | grep 'rdr/\*' >/dev/null) ; then
error_exit "rdr-anchor not found in pf.conf"
fi
2020-02-01 15:58:02 +00:00
2021-09-02 22:44:49 +02:00
# Check if ext_if is defined in pf.conf
2022-11-26 23:24:33 -05:00
EXT_IF = $( grep " ^[[:space:]]* ${ bastille_network_pf_ext_if } [[:space:]]*= " /etc/pf.conf)
2021-09-02 22:44:49 +02:00
if [ -z " ${ EXT_IF } " ] ; then
2022-11-26 23:24:33 -05:00
error_exit " bastille_network_pf_ext_if ( ${ bastille_network_pf_ext_if } ) not defined in pf.conf "
2021-09-02 22:44:49 +02:00
fi
}
2020-02-01 15:58:02 +00:00
2021-01-09 15:42:24 -07:00
# function: write rule to rdr.conf
persist_rdr_rule( ) {
if ! grep -qs " $1 $2 $3 " " ${ bastille_jailsdir } / ${ JAIL_NAME } /rdr.conf " ; then
echo " $1 $2 $3 " >> " ${ bastille_jailsdir } / ${ JAIL_NAME } /rdr.conf "
fi
}
2022-03-01 21:54:03 -05:00
persist_rdr_log_rule( ) {
proto = $1 ; host_port = $2 ; jail_port = $3 ;
shift 3;
log = $@ ;
if ! grep -qs " $proto $host_port $jail_port $log " " ${ bastille_jailsdir } / ${ JAIL_NAME } /rdr.conf " ; then
echo " $proto $host_port $jail_port $log " >> " ${ bastille_jailsdir } / ${ JAIL_NAME } /rdr.conf "
fi
}
2021-01-09 15:42:24 -07:00
# function: load rdr rule via pfctl
load_rdr_rule( ) {
( pfctl -a " rdr/ ${ JAIL_NAME } " -Psn;
2022-11-26 23:24:33 -05:00
printf '%s\nrdr pass on $%s inet proto %s to port %s -> %s port %s\n' " $EXT_IF " " ${ bastille_network_pf_ext_if } " " $1 " " $2 " " $JAIL_IP " " $3 " ) \
2021-01-09 15:42:24 -07:00
| pfctl -a " rdr/ ${ JAIL_NAME } " -f-
2023-03-28 15:03:53 +02:00
if [ -n " $JAIL_IP6 " ] ; then
( pfctl -a " rdr/ ${ JAIL_NAME } " -Psn;
printf '%s\nrdr pass on $%s inet proto %s to port %s -> %s port %s\n' " $EXT_IF " " ${ bastille_network_pf_ext_if } " " $1 " " $2 " " $JAIL_IP6 " " $3 " ) \
| pfctl -a " rdr/ ${ JAIL_NAME } " -f-
fi
2021-01-09 15:42:24 -07:00
}
2022-03-01 21:54:03 -05:00
# function: load rdr rule with log via pfctl
load_rdr_log_rule( ) {
proto = $1 ; host_port = $2 ; jail_port = $3 ;
shift 3;
log = $@
( pfctl -a " rdr/ ${ JAIL_NAME } " -Psn;
2022-11-26 23:24:33 -05:00
printf '%s\nrdr pass %s on $%s inet proto %s to port %s -> %s port %s\n' " $EXT_IF " " $log " " ${ bastille_network_pf_ext_if } " " $proto " " $host_port " " $JAIL_IP " " $jail_port " ) \
2022-03-01 21:54:03 -05:00
| pfctl -a " rdr/ ${ JAIL_NAME } " -f-
2023-03-28 15:03:53 +02:00
if [ -n " $JAIL_IP6 " ] ; then
( pfctl -a " rdr/ ${ JAIL_NAME } " -Psn;
printf '%s\nrdr pass %s on $%s inet proto %s to port %s -> %s port %s\n' " $EXT_IF " " $log " " ${ bastille_network_pf_ext_if } " " $proto " " $host_port " " $JAIL_IP6 " " $jail_port " ) \
| pfctl -a " rdr/ ${ JAIL_NAME } " -f-
fi
2022-03-01 21:54:03 -05:00
}
2020-02-01 15:58:02 +00:00
while [ $# -gt 0 ] ; do
case " $1 " in
2020-02-02 00:28:02 +00:00
list)
2021-09-02 22:44:49 +02:00
if [ " ${ TARGET } " = 'ALL' ] ; then
for JAIL_NAME in $( ls " ${ bastille_jailsdir } " | sed "s/\n//g" ) ; do
echo " ${ JAIL_NAME } redirects: "
pfctl -a " rdr/ ${ JAIL_NAME } " -Psn 2>/dev/null
done
else
check_jail_validity
pfctl -a " rdr/ ${ JAIL_NAME } " -Psn 2>/dev/null
fi
2020-02-01 15:58:02 +00:00
shift
; ;
2020-02-02 00:28:02 +00:00
clear)
2021-09-02 22:44:49 +02:00
if [ " ${ TARGET } " = 'ALL' ] ; then
for JAIL_NAME in $( ls " ${ bastille_jailsdir } " | sed "s/\n//g" ) ; do
echo " ${ JAIL_NAME } redirects: "
pfctl -a " rdr/ ${ JAIL_NAME } " -Fn
done
else
check_jail_validity
pfctl -a " rdr/ ${ JAIL_NAME } " -Fn
fi
2020-02-01 15:58:02 +00:00
shift
; ;
2021-01-09 15:42:24 -07:00
tcp| udp)
2020-02-01 15:58:02 +00:00
if [ $# -lt 3 ] ; then
usage
2022-03-01 21:54:03 -05:00
elif [ $# -eq 3 ] ; then
check_jail_validity
persist_rdr_rule $1 $2 $3
load_rdr_rule $1 $2 $3
shift 3
else
case " $4 " in
log)
proto = $1
host_port = $2
jail_port = $3
shift 3
if [ $# -gt 3 ] ; then
for last in $@ ; do
2022-07-24 22:16:38 +00:00
true
2022-03-01 21:54:03 -05:00
done
if [ $2 = = "(" ] && [ $last = = ")" ] ; then
check_jail_validity
persist_rdr_log_rule $proto $host_port $jail_port $@
load_rdr_log_rule $proto $host_port $jail_port $@
shift $#
else
usage
fi
elif [ $# -eq 1 ] ; then
check_jail_validity
persist_rdr_log_rule $proto $host_port $jail_port $@
load_rdr_log_rule $proto $host_port $jail_port $@
shift 1
else
usage
fi
; ;
*)
usage
; ;
esac
2020-02-01 15:58:02 +00:00
fi
; ;
*)
usage
; ;
esac
done