diff --git a/README.md b/README.md index f07ecf1..dbaf75c 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,156 @@ used to build, update, manage and run jails in a versioned environment. Every jail consists of layers of directories mounted on top of each other using nullfs mounts. Some of them can be shared among jails, -some are versioned. +some are versioned. By using shared and versioned layers of mounts it +is easy to update jails in a new version while the current version is +still running, you can switch back to an older version of a jail. + +Most of the layers are mounted read-only for security reasons. + +Let's take a look at the layers of a typical running jail built with `jaildk`: +``` + 1 /jail/base/12.1-RELEASE-p10 /jail/run/db read-only + 2 /dev/md12 /jail/run/db/tmp + 3 devfs /jail/run/db/dev + 4 /jail/log/db-20201026 /jail/run/db/var/log + 5 /jail/appl/db-20201026 /jail/run/db/usr/local read-only + 6 /jail/etc/db/etc-20201026 /jail/run/db/etc read-only + 7 /jail/etc/db/local-etc-20201026 /jail/run/db/usr/local/etc read-only + 8 /jail/etc/db/cron-20201026 /jail/run/db/var/cron + 9 /jail/home/db/root-20201026 /jail/run/db/root + 10 /jail/data/db/mysql-20201026 /jail/run/db/usr/local/data/mysql + 11 /backup/db /jail/run/db/var/backups + | + +--- root of the jail +``` + +As can be easily deduced this is a database jail with the following layers: + +1. **base layer**: This is basically the same as a FreeBSD base, which + contains all biinaries, libraries and other files required to boot + up a FreeBSD system. Our base doesn't contain a kernel by default, + but you could add one, required if you want to use the ports + collection and compile `lsof` yourself.
+ This particular base is based on 12.1-RELEASE-p10, that is, I + created it while I had this release installed and running on the + host system. +2. **tmp layer**: Just a ramdisk for `/tmp`, the size can be tuned. +3. **dev layer**: Contains /dev/null and friends, required by every jail. +4. **log layer**: Here we have our first versioned layer for + `/var/log`. Notice how all other layers are using the same version, + this is done by purpose (but can be changed if you like). The + version is a jail variable (see below) which is being used for all + layers. +5. **application layer**: As you know if you're using FreeBSD, any + additional software, wether installed from a port or as package, + will be installed to `/usr/local`. In our case it contains the + mysql server software, bash and a couple of supporting + utilities. It is being mounted read-only, so no new software can be + installed in the running jail. This might sound annoying at first, + because you can't just install stuff inside the jail anytime you + like. But it forces you to work more disciplined. Once a jail has + been completely built you can be sure, all components match with + each other. Read below how to install or update software in a jail. +6. **/etc layer**: this just contains the normal etc, it is basically + a stripped copy of the host `/etc`. We do not use it at all inside + a jail, but it's required nontheless. There are some exceptions + however, like `/etc/resolv.conf`. +7. **/usr/local/etc layer**: This is the place we configure all + aspects of the jail, all configs reside here (like in our case the + mysql config). It is also being mounted read-only, just like + the etc layer. +8. **cron layer**: A writable mount for the crontabs of users inside + the jail. That way one can modify crontabs with `crontab + -e`. However, if you don't want or need this, just remove the layer + and add cronjobs to `/etc/crontab`. +9. **/root layer**: most of the administrative work inside a jail must + be done as the root user and it would be a pity not to have a + writable history. So, `/root` is mounted writable to add more + comfort. +10. **a data layer**: A versioned data layer which contains the binary + data of our mysql server. This is very jail specific and you have + to add such layers yourself. Variants of such a layer include the + document root of a webserver or the repositories of a git server. +11. **backup layer**: Another custom layer, here we've mounted a + global backup directory of our host which contains all backups. + +All layers are configured in a `mount.conf` file specific for each +jail. The one for this jail looks like this: +``` +base/$base $name nullfs ro +md $name/tmp mfs rw,nosuid,async 500m 1777 +dev $name/dev devfs +log/$name-$version $name/var/log nullfs rw +appl/db-$version $name/usr/local nullfs ro +etc/$name/etc-$version $name/etc nullfs ro +etc/$name/local-etc-$version $name/usr/local/etc nullfs ro +etc/$name/cron-$version $name/var/cron nullfs rw +home/$name/root-$version $name/root nullfs rw +data/$name/mysql-$version $name/usr/local/data/mysql nullfs rw +/backup/db $name/var/backups nullfs rw +``` + +Now, as you can see, we're using variables here. Those are defined in +the `jail.conf` (not to be confused with `/etc/jail.conf` on the +host!): +``` +name=db +version=20201026 +base=12.1-RELEASE-p10 +``` + +You might wonder how the other aspects of a jail are configured like +ip addresses, routing, jail parameters, sysctls etc. Well, that's +beyond the purpose of `jaildk`. You just use the standard FreeBSD +mechanism for these things, that is `/ect/rc.conf`, `/etc/jail.conf`, +`service jail ...`, `jexec`, etc. However, `jaildk` provides some +handy wrappers to make live easier. + +For an overview of the provided commands, here's the usage screen: +``` +Usage: /usr/local/bin/jaildk + +Building Jails: +base -b [-w] - build a new base +build [-b ] [-v ] - install a build chroot of a jail +create - create a new jail from a template +clone -s -d [-o ] [-n ] - clone an existing jail or jail version +fetch - fetch current port collection + +Installing Jails: +install [-r function] - install a jail (prepare mounts, devfs etc) +uninstall [-w] - uninstall a jail +remove - remove a jail or a jail version +reinstall - stop, remove, install and start a jail + +Maintaining Jails: +start - start a jail +stop - stop a jail +restart - restart a jail +status [] - display a jail's status +rc [-r ] - execute an rc-script inside a jail + +Managing Jails: +login [] - login into a jail +blogin - chroot into a build jail + +Transferring Jails: +freeze [-a -b -v ] - freeze (build an image of) a jail +thaw - thaw (install) an image of a jail + +Getting help: +help - request help on +``` ## Installation -Execute the following command: +Download the file `jaildk` or clone this repository to your FreeBSD server and execute the following command: ``` ./jaildk setup ``` -This will create the directory structure required for the tool install -the tool itself, create a template jail and build a base directory. +This will create the directory structure required for the tool itself, +create a template jail and build a base directory. ## Basic usage @@ -37,7 +176,7 @@ Create the file `/etc/jail.conf` with the following innitial contents: sysvshm = "new"; host.hostname = $name; path = "/jail/run/$name"; - exec.prestart = "/jail/bin/jaildk install $name all start"; + exec.prestart = "/jail/bin/jaildk install $name start"; exec.clean = "true"; } @@ -52,12 +191,12 @@ Refer to [jail(8)](https://www.freebsd.org/cgi/man.cgi?query=jail&sektion=8) for Next add the following lines to your `/etc/rc.conf`: ``` -ifconfig_em0_alias0="inet 144.76.67.168/32" +ifconfig_em0_alias0="inet 172.16.1.1/32" jail_enable="YES" ``` You may need to replace the interface name `em0` with the one in use on your system. - +You might need to restart the interface to apply the alias: `/etc/rc.d/netif restart`. ### Create the jail ``` @@ -135,7 +274,7 @@ A normal base directory cannot be used with the ports collection because jaildk removes libraries and binaries for security reasons from normal bases. To create a build base, execute: -`jaildk base 12-RELEASE-build rw` +`jaildk base -b 12-RELEASE-build -w` Next, add the following entry to the configuration of you jail. To stay with our example, edit `/jail/etc/myjail/jail.conf` and add: @@ -197,7 +336,7 @@ fcgiwrap is running as pid 37682. ### Login into the running jail for administration ``` -# jaildk jlogin myjail +# jaildk login myjail ``` You can use this to login into a database or execute commands inside the jail. @@ -209,22 +348,22 @@ The very first thing to do is to update the host system using `freebsd-update`. Next create a new base version: ``` -jaildk base `uname -r` +jaildk base -b `uname -r` ``` Now you can create clone of your jail with a new version: ``` -jaildk clone myjail myjail 20201106 20210422 +jaildk clone -s myjail -d myjail -o 20201106 -n 20210422 ``` Mount the build chroot for the new version: ``` -jaildk build myjail start `uname -r` 20210422 +jaildk build myjail start -b `uname -r` -v 20210422 ``` And finally chroot into the new jail and update it: ``` -blogin myjail +jaildk blogin myjail pkg update ... ``` @@ -233,6 +372,178 @@ The last step is to remove the current running jail, change the version in `etc/ If there's anything wrong you can always go back to the previous version using the above steps. +## Advanced Features + +Jaildk also offers some advanced features like automatically setting +up and deleting ipfw rules or freezing and thawing a jail (to make it +easily portable). + +### Using the IPFW + +To use the IPFW on your host you first have to enable ipfw in your +hosts rc.conf `firewall_enable="YES"`. You probably want to set the +default firewalling-type there aswell, check out the +[FreeBSD handbook](https://www.freebsd.org/doc/handbook/firewalls-ipfw.html) +for further information. + +Once enabled you also need to start ipfw by executing the rc script: + +`/etc/rc.d/ipfw start`. + +Be aware that inter-jail communication is transfered via the loopback +interface (normally lo0) for which there is a high priority allow any +to any rule by default: + +`allow ip from any to any via lo` + +In order to control the inter-jail communication you have to delete +this rule first. + +If an ipfw.conf exists for a jail (e.g. /jail/etc/myjail/ipfw.conf) +the rules inside that config file are added when starting, and deleted +when stopping the jail. E.g. allowing HTTP/HTTPS traffic for that +jail (webserver): + +`allow tcp from any to $ip setup keep-state` + +As demonstrated in the previous rule `$ip` is reserved and +automatically replaced with the jails own ip (as reported by +`jls`). The same applies to the ipv6 address which will be available +as variable `$ip6`. Also, all variables in the jails `jail.conf` can +be used. + +In order to make these ipfw rules available on boot, you need to add +the following line to `/etc/jail.conf` in the section of the jail +which uses custom ipfw rules: + +`exec.prestart = "/jail/bin/jaildk ipfw $name"` + +Be aware, that the ipfw module will only be executed if the jail is +running so that we can properly determine the ip addresses of the +running jail. **Note**: this might change in the future. + +### Using pf + +Beside ipfw, Free supports +[pf](https://www.freebsd.org/doc/de_DE.ISO8859-1/books/handbook/firewalls-pf.html) +as well. You can use pf with `jaildk`. Unlike the ipfw module (see +above) it is a normal `install` module. That is it can be installed or +reloaded before the jail is running (i.e. like the mount module). + +In order to use `pf` with a jail, enable and configure it according to +the FreeBSD handbook linked above. It is recommended to include +general block, scrup, state rules, communication to and fro localhost +etc and just leave everything which is related to your jail. + +Just so that you know how such a global `/etc/pf.conf` file might look +like, here's a simple one: +```shell +# variables +ext = "em0" +me = "your ipv4 address here" +me5 = "your ipv6 address here/64" +loginports = "{ 22, 5222, 443 }" +icmp_types = "echoreq" + +# tables. look at the contents of a table: +# pfctl -t bad_hosts -T show +# remove an entry from a table: +# pfctl -t bad_hosts -T delete $ip +table persist + +# default policy +set block-policy drop + +# optimize according to rfc's +set optimization aggressive + +# normalisation +scrub in all +antispoof for $ext + +# allow localhost +pass quick on $local + +# additional default block rules w/ logging. to view the log: +# tcpdump -n -e -ttt -r /var/log/pflog +# to view live log: +# tcpdump -n -e -ttt -i pflog0 +block in log on $ext +block in log on $ext inet6 + +# whoever makes it into those tables: you loose +block quick from + +# allow outgoing established sessions +pass out keep state +pass out inet6 keep state + +# allow troubleshooting +pass in on $ext inet proto icmp all icmp-type $icmp_types keep state +pass in on $ext inet proto udp from any to any port 33433 >< 33626 keep state + +# allow all icmpv6 +pass in quick inet6 proto icmp6 all keep state + +# allow login but punish offenders +block quick from +pass in quick on $ext inet proto tcp from any to $me port $loginports \ + flags S/SAFR keep state \ + (max-src-conn-rate 10/60, \ + overload flush global) label ServicesTCP +pass in quick on $ext inet6 proto tcp from any to $me6 port $loginports \ + flags S/SAFR keep state \ + (max-src-conn-rate 10/60, \ + overload flush global) label ServicesTCP +``` + +Install the ruleset with `service pf start`. + +Now that everything is prepared you can create a `/jail/etc/myjail/pf.conf` file for your +jail. Here's an example I use for a webserver jail, which includes a +git server: +```shell +ip = "jail ip4 addr" +ip6 = "jail ip6 addr" +loginports = "{ 22 }" +prodports = "{ 80, 443 }" +ext = "em0" + +# dynamic block list +table + +# restrict foreigners +block quick from +pass in quick on $ext inet proto tcp from any to $ip port $loginports \ + flags S/SAFR keep state \ + (max-src-conn-rate 10/60, \ + overload flush global) label ServicesTCP + +# allow production traffic v4 +pass in quick on $ext proto tcp from any to $ip port $prodports keep state + +# allow production traffic v6 +pass in quick inet6 proto tcp from any to $ip6 port $prodports keep state +``` + +That's it already. Now install the jail as usual. You can also install +the pf ruleset for the jail separately: + +`jaildk install myjail start -r pf` + +To take look at the rules, execute: + +`jaildk install myjail status -r pf` + +You can of course manipulate the ruleset manually. `jaildk` installs +rulesets into a jail specific anchor using the following naming +scheme: `/jail/`. So, for example to view the rules, execute: + +`pfctl -a /jail/myjail -s rules` + +Manipulate a jail specific table: + +`pfctl -a /jail/myjail -t blocked -T show` ## Getting help @@ -251,6 +562,8 @@ This software is licensed under the BSD license. T.v.Dein +F.Sass (Culsu) + ## Project homepage https://github.com/TLINDEN/jaildk diff --git a/jaildk b/jaildk old mode 100644 new mode 100755 index 971bedf..9e2c928 --- a/jaildk +++ b/jaildk @@ -1,6 +1,6 @@ #!/bin/sh -version=1.07 +version=1.09 usage_jaildk() { beg=`tput -T ${TERM:-cons25} md` @@ -11,39 +11,52 @@ This is jaildk version $version, a jail management toolkit. Usage: $0 ${beg}Building Jails:${end} -base - build a new base -build - install a build chroot of a jail -create - create a new jail from a template -clone - clone an existing jail or jail version -fetch - fetch current port collection +base -b [-w] - build a new base +build [-b ] [-v ] - install a build chroot of a jail +create - create a new jail from a template +clone -s -d [-o ] [-n ] - clone an existing jail or jail version +fetch - fetch current port collection ${beg}Installing Jails:${end} -install - install a jail (prepare mounts, devfs etc) -uninstall - uninstall a jail -remove - remove a jail or a jail version -reinstall - stop, remove, install and start a jail +install [-r function] - install a jail (prepare mounts, devfs etc) +uninstall [-w] - uninstall a jail +remove - remove a jail or a jail version +reinstall - stop, remove, install and start a jail ${beg}Maintaining Jails:${end} -start - start a jail -stop - stop a jail -restart - restart a jail -status - display a jail's status -rc - execute an rc-script inside a jail +start - start a jail +stop - stop a jail +restart - restart a jail +status [] - display a jail's status +rc [-r ] - execute an rc-script inside a jail +ipfw - add or remove ipfw rules ${beg}Managing Jails:${end} -login - login into a jail (also available as separate command) -blogin - chroot into a build jail (dito) +login [] - login into a jail +blogin - chroot into a build jail ${beg}Transferring Jails:${end} -freeze - freeze (build an image of) a jail -thaw - thaw (install) an image of a jail somewhere else +freeze [-a -b -v ] - freeze (build an image of) a jail +thaw - thaw (install) an image of a jail -Run the without arguments to get usage help about the command. +${beg}Getting help:${end} +help - request help on EOF ) - echo "$usage" - exit 1 + echo "$usage" + exit 1 +} + +usage_help() { + command=$1 + + usage="usage_${command}" + if ! type "$usage" > /dev/null 2>&1; then + die "Unknown command $command!" + else + $usage + fi } ex() { @@ -67,6 +80,11 @@ bold() { echo -n "$BOLD_OFF" } +fin() { + echo "$*" >&2 + exit +} + die() { bold "$*" >&2 exit 1 @@ -101,28 +119,100 @@ die_if_not_exist() { fi } +parse_jail_conf() { + # + # just in case we want or have to fetch variables out of + # /etc/jail.conf, this is the way to go. Call it like this: + # + # ip=`parse_jail_conf $jail ip4.addr` + # + # Output may be empty, so check before using. Multiple variables + # of the same type (like multiple ip addresses) will be returned + # comma separated. + jail=$1 + search=$2 + JAIL='' + list='' + + # fetch 20 lines after "^$jail {", ignore comments + egrep -A20 "^$jail" jail.conf | egrep -v "^ *#" | \ + # turn each line into an evaluable shell expression \ + sed -e 's/ *{//g' -e 's/}//g' -e 's/ *= */=/g' -e 's/;$//' | \ + # ignore empty lines \ + egrep -v '^$' | while read LINE; do + if echo "$LINE" | egrep -q "="; then + case $JAIL in + $jail) + var=`echo "$LINE" | cut -d= -f1` + opt=`echo "$LINE" | cut -d= -f2 | sed -e 's/^"//' -e 's/"$//'` + case $var in + $search) + if test -z "$list"; then + list="$opt" + else + list="$list,$opt" + fi + ;; + esac + ;; + *) + echo $list + return + ;; + esac + else + case $LINE in + \*) JAIL=any;; + *) JAIL="$LINE";; + esac + fi + done +} + + + +usage_build() { + fin "Usage: $0 build [] [-b ] [-v ] +Mount to $j/build read-writable for maintenance. Options: +-b Use specified . default: use configured base. +-v Mount of . + One of start, stop or status. default: start." +} + jaildk_build() { jail=$1 mode=$2 - base=$3 - version=$4 + shift + shift + + base='' + version='' - load-jail-config $jail + while getopts "b:v:" arg; do + case $arg in + b) base=${OPTARG};; + v) version=${OPTARG};; + *) usage_build;; + esac + done if test -z "$mode"; then - echo "Usage: $0 build [] []" - exit 1 + mode=start fi + die_if_not_exist $jail $version + + load-jail-config $jail + if test -n "$buildbase"; then base="$buildbase" elif test -z "$base"; then - # not configured, use default: latest + # nothing configured, use default: latest base=`ls $j/base | tail -1` fi # install the jail to build/ - jaildk_install $jail all $mode rw $base $version + jaildk_install $jail $mode -r all -w -b $base -v $version case $mode in start) @@ -133,12 +223,40 @@ jaildk_build() { esac } +jaildk_rc_pf() { + jail=$1 + mode=$2 + conf=$j/etc/$jail/pf.conf + + # FIXME: maybe we use parse_jail_conf() to fetch ip addresses, + # generate a config file containing pf macros, which the user + # needs to include in the jails pf.conf? On the other hand, + # there's not that much duplication in the config. So, maybe not. + if test -f $conf; then + case $mode in + start) + bold "Installing PF rules for jail $jail:" + pfctl -a /jail/$jail -f $conf -v + ;; + status) + bold "PF rules for jail $jail:" + pfctl -a /jail/$jail -s rules -v + ;; + stop) + bold "Removing PF rules for jail $jail:" + pfctl -a /jail/$jail -f $conf -v -F all + ;; + esac + fi +} + jaildk_rc_mtree() { jail=$1 mode=$2 base=$3 version=$4 rw=$5 + rcscript=mtree if [ $mode = "start" ]; then if test -n "$rw"; then @@ -342,46 +460,57 @@ jaildk_rc_mount() { done } -jaildk_install_usage() { - err "Usage: $0 install [[] ]" - err "If is 'all' every script will be executed in rc-order." - err "If is not specified, just execute all scripts with ." - err "Available rc.d-scripts: $RCSCRIPTS_START" - exit 1 + + +usage_install() { + fin "Usage: $0 install [] [-r rc-function] +Install according to its config. Options: + Mode can either be start, stop or status. default: start +-r Only execute function with parameter. default: all. + +Available rc.d-scripts: $RCSCRIPTS_START" } jaildk_install() { jail=$1 - rcd=$2 - mode=$3 + mode=$2 + shift + shift + rcd='' - # used by jaildk_build() only - rw=$4 - base=$5 - version=$6 + # options -b -w -v are undocumented, used by jaildk_build() only + rw='' + base='' + version='' + + while getopts "r:b:v:w" arg; do + case $arg in + w) rw=1;; + b) base=${OPTARG};; + v) version=${OPTARG};; + r) rcd=${OPTARG};; + *) usage_install;; + esac + done if test -z "$jail"; then - jaildk_install_usage - fi - - if test -z "$rcd"; then - # default just install all - mode=start - rcd=all - else - case $rcd in - start|stop|restart|status) - # shift args - mode=$rcd - rcd=all - ;; - esac + usage_install fi if test -z "$mode"; then - jaildk_install_usage + mode=start fi + if test -z "$rcd"; then + # default just install everything + rcd=all + fi + + case $mode in + start|stop|restart|status) :;; + *) usage_install;; + esac + die_if_not_exist $jail if test "$rcd" = "all"; then @@ -410,14 +539,27 @@ jaildk_install() { done } +usage_uninstall() { + fin "Usage: $0 uninstall [-w] +Uninstall . Options: +-w Uninstall writable build chroot." +} + jaildk_uninstall() { # wrapper around _install jail=$1 - rw=$2 + shift + rw='' + + while getopts "w" arg; do + case $arg in + w) rw=1;; + *) usage_uninstall;; + esac + done if test -z "$jail"; then - err "Usage: $0 uninstall []" - exit 1 + usage_uninstall fi die_if_not_exist $jail @@ -426,18 +568,34 @@ jaildk_uninstall() { die "Jail $jail($version) is still running, stop it before removing!" fi - jaildk_install $jail all stop $rw + jaildk_install $jail stop -r all -w +} + + +usage_base() { + fin "Usage: $0 base -b [-w] +Build a base directory from bsd install media. Options: +-b can be the name of a base (e.g. 12.2-RELEASE) + or a directory where it shall be created +-w Create a writable base, including compiler and other + build stuff. Use this if you want to use the ports + collection." } jaildk_base() { - base=$1 - rw=$2 + base="" + rw="" + + while getopts "b:w" arg; do + case $arg in + w) rw=1;; + b) base=${OPTARG};; + *) usage_base;; + esac + done if test -z "$base"; then - err "Usage: $0 base []" - err "If the has been set, the base will not cleaned up" - err "and will contain compilers and other build stuff. Use" - err "this if you want to use the ports collection." + usage_base fi removelist="tests @@ -515,7 +673,7 @@ var/tmp" exit 1 else ex mkdir -p $basedir - bsdinstall jail $basedir + bsdinstall jail $basedir || exit 1 if test -z "$rw"; then # run base @@ -565,21 +723,40 @@ clone() { fi } +usage_clone() { + fin "Usage: $0 clone -s -d [-o ] [-n ] +-s Source jail to clone from +-d Destionation jail to create from source +-o Old version +-n New version + +Hints: +- if no source version has been given, tha latest version will be used. +- if no new version has been given, source version will be used. +- if source and new jail are the same, both versions must be given + and a new version of the same jail will be created (update)" +} + jaildk_clone() { - src=$1 - new=$2 - srcversion=$3 - newversion=$4 - update="" + src='' + new='' + srcversion='' + newversion='' + update='' + + while getopts "s:d:o:n:" arg; do + case $arg in + o) srcversion=${OPTARG};; + n) newversion=${OPTARG};; + s) src=${OPTARG};; + d) new=${OPTARG};; + *) usage_clone;; + esac + done + if test -z "$new"; then - echo "Usage: $0 clone [ []]" - echo "Hints:" - echo "- if no source version has been given, tha latest version will be used." - echo "- if no new version has been given, source version will be used." - echo "- if source and new jail are the same, both versions must be given" - echo " and a new version of the same jail will be created (update)" - exit 1 + usage_clone fi if test "$src" = "$new"; then @@ -620,7 +797,7 @@ jaildk_clone() { clone $j/data/$src/www $j/data/$new/www clone $j/data/$src/spool $j/data/$new/spool - ex cp -pRp $j/etc/$src/mount.conf $j/etc/$src/ports.conf $j/etc/$src/mtree.conf $j/etc/$new/ + ex cp -pRp $j/etc/$src/mount.conf $j/etc/$src/ports.conf $j/etc/$src/mtree.conf $j/etc/$src/ipfw.conf $j/etc/$new/ echo "Creating $j/etc/$src/jail.conf" cat $j/etc/$src/jail.conf | egrep -v "^(name|version)=" > $j/etc/$new/jail.conf @@ -656,17 +833,26 @@ jaildk_clone() { echo else . $j/etc/$src/jail.conf + jail=$new bold "To mount the build chroot of the new jail, execute:" echo "jaildk build $new start $base $newversion" fi } +usage_create() { + fin "Usage: $0 create +Create a new jail from template." +} + jaildk_create() { jail=$1 + # $jail gets overwritten in jaildk_clone or some subcall to .template :-( ... + newjail=$jail + src=.template if test -z "$jail"; then - die "Usage: $0 create " + usage_create fi . $j/etc/$src/jail.conf @@ -674,8 +860,15 @@ jaildk_create() { newversion=`date +%Y%m%d` mkdir -p $j/etc/$jail - - jaildk_clone $src $jail $srcversion $newversion + + jaildk_clone -s $src -d $jail -o $srcversion -n $newversion + # some perl magic to extract the hostname (if any) from /etc/jail.conf - and write it into the jails rc.conf + jailhostname=$(cat /etc/jail.conf | tr -d '\t\r\n ' | perl -ne '$_ =~ /.*'"$newjail"'(\{(?:\{.*\}|[^{])*\})|\w+/; print $1;' | grep -oE 'hostname=[^;]+' | cut -d= -f2) + if [ -n "$jailhostname" ]; then + echo "new name: $jailhostname" + echo "in path $j/etc/$jail/local-etc-$newversion/rc.conf" + sed -iE 's/^hostname.*$/hostname="'"$jailhostname"'"/' $j/etc/$newjail/local-etc-$newversion/rc.conf + fi } remove() { @@ -688,12 +881,25 @@ remove() { fi } +usage_remove() { + fin "Usage: $0 remove [-v ] +Remove from disk." +} + jaildk_remove() { jail=$1 - version=$2 + shift + version='' + + while getopts "v:" arg; do + case $arg in + v) version=${OPTARG};; + *) usage_remove;; + esac + done if test -z "$jail"; then - die "Usage: $0 remove []" + usage_remove fi if jls | egrep -q "${jail}"; then @@ -726,19 +932,37 @@ jaildk_remove() { } jaildk_jail_usage() { - die "Usage: $0 | status" + fin "Usage: $0 | status" +} + +usage_start() { + fin "Usage $0 start +Start ." +} + +usage_stop() { + fin "Usage $0 stop +Stop ." +} + +usage_restart() { + fin "Usage $0 restart +Restart ." +} + +usage_status() { + fin "Usage $0 status [] +Show status of . Without , show status of all jails." } jaildk_jail() { - mode=$1 jail=$2 + mode=$1 - if test -z "$mode"; then - jaildk_jail_usage - fi - - if test -z "$jail" -a $mode = "status"; then + if test -z "$jail"; then + usage_$mode + elif test -z "$jail" -a $mode = "status"; then bold "Running jails:" bold " JID IP Address Hostname Path" jls | grep -v JID @@ -754,8 +978,6 @@ jaildk_jail() { jls | grep -v JID | awk '{print $3}' | while read J; do jaildk_rc $J status done - elif test -z "$jail"; then - jaildk_jail_usage else bold "Jail $jail $mode:" case $mode in @@ -765,6 +987,7 @@ jaildk_jail() { ;; *) service jail $mode $jail + jaildk_ipfw $jail $mode ;; esac fi @@ -783,35 +1006,33 @@ get_rc_scripts() { done } -jaildk_rc_usage() { - err "Usage: $0 rc { [] | }" - err "If is all, execute for every rc script" - err " must be a parameter of " - err "if only has been given, execute all scripts" - exit 1 +usage_rc() { + fin "Usage: $0 rc [] [-r with parameter . Options: +-r Execute . default: execute all enabled scripts." } jaildk_rc() { jail=$1 - rc=$2 - mode=$3 + mode=$1 + shift + shift + + rc='' + + while getopts "r:" arg; do + case $arg in + r) rcd=${OPTARG};; + *) usage_rc;; + esac + done if test -z "$rc"; then - jaildk_rc_usage + rc='all' fi - if test -z "$mode"; then - # shift args - case $rc in - start|stop|restart|status) - # shift args - mode=$rc - rc=all - ;; - *) - jaildk_rc_usage - ;; - esac + if test -z "$jail" -o -z "$mode"; then + usage_rc fi if ! jls | egrep -q "${jail}"; then @@ -840,6 +1061,14 @@ jaildk_rc() { fi } +usage_blogin() { + err "Usage: $file +Chroot into a build jail. + +Mounted build chroot's:" + mount|egrep "base.*build" | awk '{print $3}' | cut -d/ -f 4 + exit 1 +} jaildk_blogin() { jail=$1 @@ -851,10 +1080,7 @@ jaildk_blogin() { else file="$0" fi - echo "Usage: $file []" - echo "mounted build jails:" - mount|egrep "base.*build" | awk '{print $3}' | cut -d/ -f 4 - exit + usage_blogin fi chroot="$j/build/$jail" @@ -878,6 +1104,16 @@ jaildk_blogin() { env - HOME=$home TERM=$term SHELL=$shell PATH=$path chroot $chroot $shell } +usage_login() { + err "Usage: $file [] +Login into a jail by name, ip or domain. If has not been +specified, login as root. + +Available jails:" + jls + exit 1 +} + jaildk_login() { jail=$1 user=$2 @@ -891,10 +1127,7 @@ jaildk_login() { else file="$0" fi - echo "Usage: $file []" - echo "available jails:" - jls - exit + usage_login fi jid="" @@ -932,10 +1165,19 @@ jaildk_login() { env - JAIL=$jail HOME=$home TERM=$term SHELL=$shell PATH=$path $jexec -U $user $jid $shell } +usage_reinstall() { + fin "Usage: $0 reinstall +Stop, uninstall, install and start . +" +} jaildk_reinstall() { jail=$1 + if test -z "$jail"; then + usage_reinstall + fi + die_if_not_exist $jail if jls | egrep -q "${jail}"; then @@ -960,7 +1202,7 @@ jaildk_setup() { j=$1 if test -z "$j"; then - die "Usage: $0 setup " + fin "Usage: $0 setup " fi bold "preparing directories" @@ -1005,8 +1247,10 @@ home/$name/root-$version $name/root nullfs rw' > bold "creating template config $j/etc/.template/ports.conf" (echo bash; echo ca_root_nss) > $j/etc/.template/ports.conf + bold "creating template config $j/etc/.template/ipfw.conf" + touch $j/etc/.template/ipfw.conf + bold "creating template config $j/etc/.template/mtree.conf" -# touch $j/etc/.template/mtree.conf echo '/set type=dir uid=0 gid=0 mode=01777 . type=dir mode=0755 tmp @@ -1063,7 +1307,7 @@ endif read yesno case $yesno in y|Y|yes|YES) - jaildk_base $j/base/$os + jaildk_base -b $j/base/$os ;; esac } @@ -1092,7 +1336,7 @@ jaildk_fetch_ports() { ex rm -rf $j/ports/tmp/ports* } -freeze_usage() { +usage_freeze() { echo "Usage: $0 freeze [options] Options: -v freeze of @@ -1123,12 +1367,12 @@ jaildk_freeze() { a) ADDAPPL=1;; b) ADDBASE=1;; v) VERSION=${OPTARG};; - *) freeze_usage;; + *) usage_freeze;; esac done if test -z "$jail"; then - freeze_usage + usage_freeze fi die_if_not_exist $jail "Jail to freeze" $VERSION @@ -1231,9 +1475,12 @@ thaw_tarball() { ex rm -f $srcdir/$tarball } +usage_thaw() { + fin "Usage: $0 thaw " +} + jaildk_thaw() { image=$1 - J=$2 # just for testing if test -n "$J"; then j=$J @@ -1243,8 +1490,7 @@ jaildk_thaw() { version=$(echo $image | cut -d\- -f3 | cut -d\. -f1) if ! test -n "$version" -o -n "$jail"; then - err "Usage: $0 thaw " - die "Image filename pattern: --.tgz" + usage_thaw fi if test -d $j/etc/$jail/etc-$version; then @@ -1301,6 +1547,69 @@ jaildk_thaw() { bold "Done. Thawed jail $jail $version from $image." } +usage_ipfw() { + echo "Usage: $0 ipfw +[Un]install ipfw rules. can be start or stop. +The jail needs to have a ipfw.conf file, containing +ipfw rules. You can use variables like \$ip and \$ip6 +and you need to omit the 'ipfw add' of the command." + exit 1 +} + +jaildk_ipfw() { + jail=$1 + mode=$2 + + if test -z "$mode"; then + usage_ipfw + fi + + if test -f "$j/etc/$jail/ipfw.conf"; then + echo + bold "Managing IPFW Rules..." + case $mode in + start) + jaildk_ipfw_delete $jail "y" + jaildk_ipfw_add $jail + ;; + stop) + jaildk_ipfw_delete $jail + ;; + esac + bold "... done" + echo + fi +} + +jaildk_ipfw_add() { + jail=$1 + + # support jail variables as well + load-jail-config $jail + + # Getting current jails IP.. + ip=`jls -n -j $jail ip4.addr | cut -d= -f2` + if test -z "$ip"; then + die "Jail $jail doesn't have an ipv4 address!" + fi + + ip6=`jls -n -j $jail ip6.addr | cut -d= -f2` # optional, no checks + + # Adding rules + egrep "^[a-z]" $j/etc/$jail/ipfw.conf | while read LINE; do + rule=$(eval echo "ipfw add $LINE // $jail") + echo $rule + $rule + done +} + +jaildk_ipfw_delete() { + jail=$1 + noout=$2 + # Deleting rules + ipfw show | grep -E "// $jail\$" | while read rule; do [ -z "$2" ] && bold "Deleting rule $rule"; sh -c "ipfw delete $(echo $rule| awk '{print $1}')"; done + +} ########################## # @@ -1310,8 +1619,8 @@ jaildk_thaw() { JAILDIR=/jail # install modules -RCSCRIPTS_START="jaildk_rc_mount jaildk_rc_rcoff jaildk_rc_ports jaildk_rc_mtree" -RCSCRIPTS_STOP="jaildk_rc_rcoff jaildk_rc_mount jaildk_rc_ports" +RCSCRIPTS_START="jaildk_rc_mount jaildk_rc_rcoff jaildk_rc_ports jaildk_rc_mtree jaildk_rc_pf" +RCSCRIPTS_STOP="jaildk_rc_pf jaildk_rc_rcoff jaildk_rc_mount jaildk_rc_ports" # globals j=$JAILDIR @@ -1328,9 +1637,12 @@ case $runner in start|stop|status|restart) jaildk_jail $runner $* ;; - setup|reinstall|install|uninstall|build|blogin|login|clone|create|remove|rc|base|fetch|freeze|thaw) + setup|reinstall|install|uninstall|build|blogin|login|clone|create|remove|rc|base|fetch|freeze|thaw|ipfw) jaildk_$runner $* ;; + help) + usage_help $* + ;; *) usage_jaildk $* ;;