Skip to content

Instantly share code, notes, and snippets.

@paulc
Last active April 8, 2021 22:16
Show Gist options
  • Save paulc/cc561978122b7c9736dc4e4502e56cc5 to your computer and use it in GitHub Desktop.
Save paulc/cc561978122b7c9736dc4e4502e56cc5 to your computer and use it in GitHub Desktop.
Another jail wrapper
#!/bin/sh
set -e
JAIL_IF=${JAIL_IF:-lo1}
JAIL_IP=172.16.0
JAIL_MAX=16
clean() {
set +e
for j in $(jls jid)
do
jail -r $j
done
service zfs stop
service pf onestop
zpool destroy -f pool
rm -f /zpool
ifconfig $JAIL_IF destroy
sysrc -x gateway_enable zfs_enable pf_enable cloned_interfaces
}
init() {
sysrc gateway_enable=yes
sysrc pf_enable=no
sysrc zfs_enable=yes
sysrc jail_enable=yes
sysrc cloned_interfaces=$JAIL_IF
service zfs start
cat >/etc/jail.conf <<EOM
interface = "$JAIL_IF";
host.hostname = "\$name";
ip4.addr = "$JAIL_IP.\$ip";
path = "/jail/run/\$name";
exec.prestart = "$(readlink -f $0) pf_rules | lockf /tmp/pf-jail.lock pfctl -a jail -f -";
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
allow.chflags;
mount.devfs;
exec.clean;
EOM
cat >/etc/pf.conf <<'EOM'
ext_if = "hn0"
jail_if = "lo1"
nat-anchor jail
rdr-anchor jail
EOM
ifconfig lo1 create
sysctl net.inet.ip.forwarding=1
service pf onestart
}
dist() {
truncate -s 8G /zpool
zpool create pool /zpool
zfs create -o mountpoint=/jail -o compression=lz4 pool/jail
zfs create pool/jail/run
local release=$(sysctl -n kern.osrelease | sed -e 's/-p[0-9]*$//')
local arch=$(sysctl -n hw.machine_arch)
local dist=http://ftp.freebsd.org/pub/FreeBSD/releases/$arch/$release
local template_dir=/jail/template-$arch
local f
zfs create pool$template_dir
for f in base.txz doc.txz $([ $arch = amd64 ] && echo lib32.txz)
do
fetch -o - $dist/$f | tar -C $template_dir -xf -
done
zfs snapshot pool$template_dir@dist
if [ $arch = amd64 ]
then
arch=i386
local dist=http://ftp.freebsd.org/pub/FreeBSD/releases/$arch/$release
local template_dir=/jail/template-$arch
zfs create pool$template_dir
for f in base.txz doc.txz
do
fetch -o - $dist/$f | tar -C $template_dir -xf -
done
zfs snapshot pool$template_dir@dist
fi
}
configure() {
local t f
for t in /jail/template-*
do
sysrc -f $t/etc/rc.conf sendmail_enable=NO \
sendmail_submit_enable=NO \
sendmail_outbound_enable=NO \
sendmail_msp_queue_enable=NO \
syslogd_enable=No \
sshd_enable=YES \
sshd_flags="-o PermitRootLogin=yes"
/usr/sbin/pw -R $t usermod -n root -w no -s /bin/sh
for f in /etc/resolv.conf /etc/localtime
do
cp $f $t/$f
done
zfs snapshot pool$t@base
done
}
next_ip() {
awk -v max=$JAIL_MAX -f - /etc/jail.conf <<'EOM'
function strip(s) {gsub("^[ \t\n\"]+","",s);gsub("[ \t\n\"]+$","",s);return s}
function readblock(l) {l=$0;while($NF != "}"){getline;l=l$0};return l }
$1 ~ "[a-zA-Z0-9]+" && $2 == "{" {
split(readblock(),a,";|}|{|=")
name = strip(a[1])
for (i=2;i<length(a);i=i+2) {
k = strip(a[i])
if (k == "$ip") { ip[strip(a[i+1])]=name }
}
}
END { for (i=1;i<max;++i) { if (ip[i] == "") { print i; exit }}}
EOM
}
pf_rules() {
awk -v jail_ip=$JAIL_IP -f - /etc/jail.conf <<'EOM'
function parray(a) {for (i in a) { print i ":" a[i] }}
function strip(s) {gsub("^[ \t\n\"]+","",s);gsub("[ \t\n\"]+$","",s);return s}
function readblock(l) {l=$0;while($NF != "}"){getline;l=l$0};return l }
BEGIN {
printf("ext_if = \"hn0\"\n")
printf("jail_if = \"lo1\"\n")
}
$1 ~ "[a-zA-Z0-9]+" && $2 == "{" {
delete ports
split(readblock(),a,";|}|{|=")
name = strip(a[1])
for (i=2;i<length(a);i=i+2) {
k = strip(a[i])
if (k == "$ip") { ip = strip(a[i+1]) }
if (k == "$ports") { split(strip(a[i+1]),ports,",") }
}
printf("nat on $ext_if from %s.%d to any -> $ext_if\n",jail_ip,ip)
for (p in ports) {
split(ports[p],a,":")
printf("rdr on $ext_if inet proto tcp to port %d -> %s.%d port %d\n",a[1],jail_ip,ip,a[2])
}
}
EOM
}
pf_reload() {
pf_rules | pfctl -a jail -f - -vP
}
new() {
local name=${1:?Usage: $0 new <name> [arch]}
local arch=${2:-$(sysctl -n hw.machine_arch)}
local ip=$(next_ip)
: ${ip:?Error: Cant allocate Jail IP}
if [ -d /jail/run/$name ]
then
echo "Error: Path /jail/run/$name exists"
exit
fi
zfs clone pool/jail/template-$arch@base pool/jail/run/$name
sysrc -f /jail/run/$name/etc/rc.conf hostname=$name
pw -R /jail/run/$name usermod root -w random
printf "%s { \$ip = %d; \$ports = \"%d:22\"; }\n" $name $ip $((3000+$ip)) >> /etc/jail.conf
pf_rules | pfctl -a jail -f - -v
jail -c $name
}
remove() {
local name=${1:?Usage: $0 remove <name>}
jls -j $name >/dev/null 2>&1 && jail -r $name
sed -i .old -e '/^ *'${name}' [^}]*$/,/} *$/d' -e '/^ *'${name}'.*} *$/d' /etc/jail.conf
zfs destroy pool/jail/run/$name
pf_rules | pfctl -a jail -f - -v
}
# Main
cmd=$1
shift
if [ $cmd = "help" ]
then
echo "Usage: $0"
echo
sed -ne 's/^\([A-Za-z0-9\-_]*\)().*/ \1/p' $0
else
$cmd $@
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment