Skip to content

Commit

Permalink
Merge pull request #119 from paulc/master
Browse files Browse the repository at this point in the history
Add support for dynamic redirection of host/container ports
  • Loading branch information
cedwards authored Feb 2, 2020
2 parents f5ddc43 + d8914f9 commit 503f787
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 4 deletions.
51 changes: 50 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Available Commands:
import Import a specified container.
list List containers (running and stopped).
pkg Manipulate binary packages within targeted container(s). See pkg(8).
rdr Redirect host port to container port.
restart Restart a running container.
service Manage services within targeted container(s).
start Start a stopped container.
Expand Down Expand Up @@ -117,13 +118,21 @@ set skip on lo
table <jails> persist
nat on $ext_if from <jails> to any -> ($ext_if)
## rdr example
## static rdr example
## rdr pass inet proto tcp from any to any port {80, 443} -> 10.17.89.45
# Enable dynamic rdr (see below)
rdr-anchor "rdr/*"
block in all
pass out quick modulate state
antispoof for $ext_if inet
pass in inet proto tcp from any to any port ssh flags S/SA keep state
# make sure you also open up ports that you are going to use for dynamic rdr
# pass in inet proto tcp from any to any port <rdr-start>:<rdr-end> flags S/SA keep state
# pass in inet proto udp from any to any port <rdr-start>:<rdr-end> flags S/SA keep state
```
* Make sure to change the `ext_if` variable to match your host system interface.
Expand All @@ -150,6 +159,24 @@ container at `10.17.89.45`.
Finally, enable and (re)start the firewall:
## dynamic rdr
The `rdr-anchor "rdr/*"` enables dynamic rdr rules to be setup using the
`bastille rdr` command at runtime - eg.
```
bastille rdr <jail> tcp 2001 22 # Redirects tcp port 2001 on host to 22 on jail
bastille rdr <jail> udp 2053 53 # Same for udp
bastille rdr <jail> list # List dynamic rdr rules
bastille rdr <jail> clear # Clear dynamic rdr rules
```
Note that if you are rediirecting ports where the host is also listening
(eg. ssh) you should make sure that the host service is not listening on
the cloned interface - eg. for ssh set sshd_flags in rc.conf
## Enable pf rules
```shell
ishmael ~ # sysrc pf_enable="YES"
ishmael ~ # service pf restart
Expand Down Expand Up @@ -722,6 +749,28 @@ ishmael ~ # bastille cp ALL /tmp/resolv.conf-cf etc/resolv.conf
/tmp/resolv.conf-cf -> /usr/local/bastille/jails/unbound0/root/etc/resolv.conf
```
bastille-rdr
------------
`bastille rdr` allows you to configure dynamic rdr rules for your containers
without modifying pf.conf (assuming you are using the `bastille0` interface
for a private network and have enabled `rdr-anchor 'rdr/*'` in /etc/pf.conf
as described in the Networking section).
```shell
# bastille rdr --help
Usage: bastille rdr TARGET [clear] | [list] | [tcp <host_port> <jail_port>] | [udp <host_port> <jail_port>]
# bastille rdr dev1 tcp 2001 22
# bastille rdr dev1 list
rdr on em0 inet proto tcp from any to any port = 2001 -> 10.17.89.1 port 22
# bastille rdr dev1 udp 2053 53
# bastille rdr dev1 list
rdr on em0 inet proto tcp from any to any port = 2001 -> 10.17.89.1 port 22
rdr on em0 inet proto udp from any to any port = 2053 -> 10.17.89.1 port 53
# bastille rdr dev1 clear
nat cleared
```
bastille update
---------------
The `update` command targets a release instead of a container. Because every
Expand Down
28 changes: 26 additions & 2 deletions docs/chapters/networking.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,21 @@ Create the firewall rules:
table <jails> persist
nat on $ext_if from <jails> to any -> ($ext_if)
## rdr example
## static rdr example
## rdr pass inet proto tcp from any to any port {80, 443} -> 10.17.89.45
## dynamic rdr anchor (see below)
rdr-anchor "rdr/*"
block in all
pass out quick modulate state
antispoof for $ext_if inet
pass in inet proto tcp from any to any port ssh flags S/SA modulate state
# If you are using dynamic rdr also need to ensure that the external port
# range you are using is open
# pass in inet proto tcp any to any port <rdr-start>:<rdr-end>
- Make sure to change the `ext_if` variable to match your host system interface.
- Make sure to include the last line (`port ssh`) or you'll end up locked out.

Expand All @@ -121,7 +128,7 @@ to containers are:
nat on $ext_if from <jails> to any -> ($ext_if)
## rdr example
## static rdr example
## rdr pass inet proto tcp from any to any port {80, 443} -> 10.17.89.45
The `nat` routes traffic from the loopback interface to the external
Expand All @@ -131,6 +138,23 @@ The `rdr pass ...` will redirect traffic from the host firewall on port X to
the ip of Container Y. The example shown redirects web traffic (80 & 443) to the
containers at `10.17.89.45`.

## dynamic rdr anchor (see below)
rdr-anchor "rdr/*"
The `rdr-anchor "rdr/*"` enables dynamic rdr rules to be setup using the
`bastille rdr` command at runtime - eg.

bastille rdr <jail> tcp 2001 22 # Redirects tcp port 2001 on host to 22 on jail
bastille rdr <jail> udp 2053 53 # Same for udp
bastille rdr <jail> list # List dynamic rdr rules
bastille rdr <jail> clear # Clear dynamic rdr rules

Note that if you are redirecting ports where the host is also listening
(eg. ssh) you should make sure that the host service is not listening on
the cloned interface - eg. for ssh set sshd_flags in rc.conf

sshd_flags="-o ListenAddress=<hostname>"

Finally, start up the firewall:

.. code-block:: shell
Expand Down
28 changes: 28 additions & 0 deletions docs/chapters/subcommands/rdr.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
===
rdr
===

`bastille rdr` allows you to configure dynamic rdr rules for your containers
without modifying pf.conf (assuming you are using the `bastille0` interface
for a private network and have enabled `rdr-anchor 'rdr/*'` in /etc/pf.conf
as described in the Networking section).

Note: you need to be careful if host services are configured to run
on all interfaces as this will include the jail interface - you should
sepcify the interface they run on in rc.conf (or other config files)

.. code-block:: shell
# bastille rdr --help
Usage: bastille rdr TARGET [clear] | [list] | [tcp <host_port> <jail_port>] | [udp <host_port> <jail_port>]
# bastille rdr dev1 tcp 2001 22
# bastille rdr dev1 list
rdr on em0 inet proto tcp from any to any port = 2001 -> 10.17.89.1 port 22
# bastille rdr dev1 udp 2053 53
# bastille rdr dev1 list
rdr on em0 inet proto tcp from any to any port = 2001 -> 10.17.89.1 port 22
rdr on em0 inet proto udp from any to any port = 2053 -> 10.17.89.1 port 53
# bastille rdr dev1 clear
nat cleared
3 changes: 2 additions & 1 deletion usr/local/bin/bastille
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ Available Commands:
import Import a specified container.
list List containers (running and stopped).
pkg Manipulate binary packages within targeted container(s). See pkg(8).
rdr Redirect host port to container port.
restart Restart a running container.
service Manage services within targeted container(s).
start Start a stopped container.
Expand Down Expand Up @@ -130,7 +131,7 @@ esac

# Filter out all non-commands
case "${CMD}" in
cmd|convert|cp|create|destroy|export|import|list|pkg|restart|start|stop|sysrc|template|verify)
cmd|convert|cp|create|destroy|export|import|list|pkg|rdr|restart|start|stop|sysrc|template|verify)
;;
update|upgrade)
;;
Expand Down
118 changes: 118 additions & 0 deletions usr/local/share/bastille/rdr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/bin/sh
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * 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.
#
# * 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.
#
# 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.

. /usr/local/share/bastille/colors.pre.sh
. /usr/local/etc/bastille/bastille.conf

usage() {
echo -e "${COLOR_RED}Usage: bastille rdr TARGET [clear] | [list] | [tcp <host_port> <jail_port>] | [udp <host_port> <jail_port>]${COLOR_RESET}"
exit 1
}

# Handle special-case commands first.
case "$1" in
help|-h|--help)
usage
;;
esac

if [ $# -lt 2 ]; then
usage
fi

TARGET="${1}"
shift

# Can only redirect to single jail
if [ "${TARGET}" = 'ALL' ]; then
echo -e "${COLOR_RED}Can only redirect to single jail${COLOR_RESET}"
exit 1
fi

# Check jail name valid
JAIL_NAME=$(jls -j "${TARGET}" name 2>/dev/null)
if [ -z "${JAIL_NAME}" ]; then
echo -e "${COLOR_RED}Jail not found: ${TARGET}${COLOR_RESET}"
exit 1
fi

# Check jail ip4 address valid
JAIL_IP=$(jls -j "${TARGET}" ip4.addr 2>/dev/null)
if [ -z "${JAIL_IP}" -o "${JAIL_IP}" = "-" ]; then
echo -e "${COLOR_RED}Jail IP not found: ${TARGET}${COLOR_RESET}"
exit 1
fi

# Check rdr-anchor is setup in pf.conf
if !(pfctl -sn | grep rdr-anchor | grep 'rdr/\*' >/dev/null); then
echo -e "${COLOR_RED}rdr-anchor not found in pf.conf${COLOR_RESET}"
exit 1
fi

# Check ext_if is setup in pf.conf
EXT_IF=$(grep '^[[:space:]]*ext_if[[:space:]]*=' /etc/pf.conf)
if [ -z "${JAIL_NAME}" ]; then
echo -e "${COLOR_RED}ext_if not defined in pf.conf${COLOR_RESET}"
exit 1
fi

while [ $# -gt 0 ]; do
case "$1" in
list)
pfctl -a "rdr/${JAIL_NAME}" -Psn 2>/dev/null
shift
;;
clear)
pfctl -a "rdr/${JAIL_NAME}" -Fn
shift
;;
tcp)
if [ $# -lt 3 ]; then
usage
fi
( pfctl -a "rdr/${JAIL_NAME}" -Psn;
printf '%s\nrdr on $ext_if inet proto tcp to port %d -> %s port %d\n' "$EXT_IF" "$2" "$JAIL_IP" "$3" ) \
| pfctl -a "rdr/${JAIL_NAME}" -f-
shift 3
;;
udp)
if [ $# -lt 3 ]; then
usage
fi
( pfctl -a "rdr/${JAIL_NAME}" -Psn;
printf '%s\nrdr on $ext_if inet proto udp to port %d -> %s port %d\n' "$EXT_IF" "$2" "$JAIL_IP" "$3" ) \
| pfctl -a "rdr/${JAIL_NAME}" -f-
shift 3
;;
*)
usage
;;
esac
done



0 comments on commit 503f787

Please sign in to comment.