! ! Warning: not much tested. ! ! ---------------------------------------------------------------------- ! ! - remove the jail__netmask option. ! - implement support for both address familes with te ! jail__ip option ! - Implement _multi support suffix for the former to ! configure additional addresses. ! The syntax is for the argument is ! [iFace|]address[{/prefix, netmask a.b.c.d, prefixlen n}] ! - In addition we still support address lists and the global and ! per jail interface setting. ! - Should permit starting of no-IP jails now as well. ! ! Based on: initial work from Ruben van Staveren. ! Discussed on: freebsd-jail in Nov 2008. ! Reviewed by: ! Approved by: ! Index: share/man/man5/rc.conf.5 =================================================================== --- share/man/man5/rc.conf.5 (revision 186887) +++ share/man/man5/rc.conf.5 (working copy) @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 24, 2008 +.Dd January 8, 2009 .Dt RC.CONF 5 .Os .Sh NAME @@ -3426,8 +3426,59 @@ .It Va jail_ Ns Ao Ar jname Ac Ns Va _ip .Pq Vt str Unset by default. -Set to the IP address assigned to jail -.Va jname . +Set to the (primary) IPv4 resp. IPv6 address(es) assigned to jail +.Pp +The options accept multiple syntaxes: +.Bl -bullet -offset indent +.It +The classic single address. +Example: +.Bd -literal +jail_example_ip="192.0.2.1" +.Ed +.It +A comma separated list of addresses. +As a speciality for backward compatibility the IPv4 list +can also take IPv6 addresses. +Examples: +.Bd -literal +jail_example_ip="192.0.2.1,192.0.2.2,192.0.2.3" +jail_example_ip="192.0.2.1,2001:db8::1,192.0.2.2,192.0.2.3" +jail_example_ip="2001:db8::1,2001:db8::2,2001:db8::3" +.Ed +.It +An optional interface name, an address and an optional prefix, +netmask or prefixlen. +In case no interface is given, the jail global or the global one +will be used to configure the alias on. +In case no netmask is given '/32' will be used for IPv4 and '/128' +will be used for IPv6. +Examples: +.Bd -literal +jail_example_ip="lo0|192.0.2.1" +jail_example_ip="lo0|192.0.2.2/27" +jail_example_ip="192.0.2.3 netmask 255.255.255.255" +jail_example_ip="lo0|2001:db8::1" +jail_example_ip="2001:db8::2/128" +jail_example_ip="lo0|2001:db8::3 prefixlen 120" +.Ed +.El +.Pp +It is also possible to add more addresses for each address +family using a +.Li _multi +suffix. +These entries follow the same syntax as their primary +entries. +Example: +.Bd -literal +jail_example_ip_multi0="lo0|192.0.2.1" +jail_example_ip_multi1="lo0|192.0.2.2/27" +jail_example_ip_multi2="192.0.2.3 netmask 255.255.255.255" +jail_example_ip_multi3="lo0|2001:db8::1" +jail_example_ip_multi4="2001:db8::2/128" +jail_example_ip_multi5="lo0|2001:db8::3 prefixlen 120" +.Ed .It Va jail_ Ns Ao Ar jname Ac Ns Va _flags .Pq Vt str Set to @@ -3440,12 +3491,6 @@ Unset by default. When set, sets the interface to use when setting IP address alias. Note that the alias is created at jail startup and removed at jail shutdown. -.It Va jail_ Ns Ao Ar jname Ac Ns Va _netmask -.Pq Vt str -Set to -.Li 255.255.255.255 -by default. -This is the IP netmask to use when setting IP address alias. .It Va jail_ Ns Ao Ar jname Ac Ns Va _fib .Pq Vt str Unset by default. Index: etc/rc.d/jail =================================================================== --- etc/rc.d/jail (revision 186887) +++ etc/rc.d/jail (working copy) @@ -39,8 +39,8 @@ _procdir="${_rootdir}/proc" eval _hostname=\"\$jail_${_j}_hostname\" eval _ip=\"\$jail_${_j}_ip\" - eval _netmask=\"\${jail_${_j}_netmask:-255.255.255.255}\" eval _interface=\"\${jail_${_j}_interface:-${jail_interface}}\" + eval _fib=\"\${jail_${_j}_fib:-${jail_fib}}\" eval _exec=\"\$jail_${_j}_exec\" eval _exec_start=\"\${jail_${_j}_exec_start:-${jail_exec_start}}\" @@ -84,7 +84,6 @@ [ -z "${_flags}" ] && _flags="-l -U root" eval _consolelog=\"\${jail_${_j}_consolelog:-${jail_consolelog}}\" [ -z "${_consolelog}" ] && _consolelog="/var/log/jail_${_j}_console.log" - eval _fib=\"\${jail_${_j}_fib:-${jail_fib}}\" # Debugging aid # @@ -94,7 +93,7 @@ debug "$_j mount enable: $_mount" debug "$_j hostname: $_hostname" debug "$_j ip: $_ip" - debug "$_j netmask: $_netmask" + jail_show_addresses ${_j} debug "$_j interface: $_interface" debug "$_j fib: $_fib" debug "$_j root: $_rootdir" @@ -128,10 +127,6 @@ if [ -z "${_rootdir}" ]; then err 3 "$name: No root directory has been defined for ${_j}" fi - if [ -z "${_ip}" ]; then - err 3 "$name: No IP address has been defined for ${_j}" - fi - } # set_sysctl rc_knob mib msg @@ -277,6 +272,200 @@ mount -a -F "${_fstab}" } +# jail_show_addresses jail +# Debug print the input for the given _multi aliases +# for a jail for init_variables(). +# +jail_show_addresses() +{ + local _j _type alias + _j="$1" + alias=0 + + if [ -z "${_j}" ]; then + warn "jail_show_addresses: you must specify a jail" + return + fi + + while : ; do + eval _addr=\"\$jail_${_j}_ip_multi${alias}\" + if [ -n "${_addr}" ]; then + debug "${_j} ip_multi${alias}: $_addr" + alias=$((${alias} + 1)) + else + break + fi + done +} + +# jail_extract_address argument +# The second argument is the string from one of the _ip +# or the _multi variables. In case of a comma separated list +# only one argument must be passed in at a time. +# The function alters the _type, _iface, _addr and _mask variables. +# +jail_extract_address() +{ + local _i + _i=$1 + + if [ -z "${_i}" ]; then + warn "jail_extract_address: called without input" + return + fi + + # Check if we have an interface prefix given and split into + # iFace and rest. + case "${_i}" in + *\|*) # ifN|.. prefix there + _iface=${_i%%|*} + _r=${_i##*|} + ;; + *) _iface="" + _r=${_i} + ;; + esac + + # In case the IP has no interface given, check if we have a global one. + _iface=${_iface:-${_interface}} + + # Set address, cut off any prefix/netmask/prefixlen. + _addr=${_r} + _addr=${_addr%%[/ ]*} + + # Theoretically we can return here if itnerface is not set, + # as we only care about the _mask if we call ifconfig. + # I am not doing this as we may want to santize IP addresses + # based on _type later, and optionally change the type as well. + # Though I admit this will be hard to get all right in shell. + + # Extract the prefix/netmask/prefixlen part by cutting off the address. + _mask=${_r} + _mask=`expr "${_mask}" : "${_addr}\(.*\)"` + + # Identify type {inet,inet6}. + case "${_addr}" in + *\.*\.*\.*) _type="inet" ;; + *:*) _type="inet6" ;; + *) _type="ERROR: type not identified" + warn "jail_extract_address: type not identified" + ;; + esac + + # Handle the special /netmask instead of /prefix or + # "netmask xxx" case for legacy IP. + # We do NOT support shortend class-full netmasks. + if [ "${_type}" = "inet" ]; then + case "${_mask}" in + /*\.*\.*\.*) _mask=" netmask ${_mask#/}" ;; + *) ;; + esac + + # In case _mask is still not set use /32. + _mask=${_mask:-/32} + + elif [ "${_type}" = "inet6" ]; then + # In case _maske is not set for IPv6, use /128. + _mask=${_mask:-/128} + fi +} + +# jail_handle_ips_option {add,del} input +# Handle a single argument imput which can be a comma separated +# list of addresses (theoretically with an option interface and +# prefix/netmask/prefixlen). +# +jail_handle_ips_option() +{ + local _x _action _type _i + _action=$1 + _x=$2 + + if [ -z "${_x}" ]; then + # No IP given. This can happen for the primary address + # of each address family. + return + fi + + # Loop, in case we find a comma separated list, we need to handle + # each argument on its own. + while [ ${#_x} -gt 0 ]; do + case "${_x}" in + *,*) # Extract the first argument and strip it off the list. + _i=`expr "${_x}" : '^\([^,]*\)'` + _x=`expr "${_x}" : "^[^,]*,\(.*\)"` + ;; + *) _i=${_x} + _x="" + ;; + esac + + _type="" + _iface="" + _addr="" + _mask="" + jail_extract_address "${_i}" + + # make sure we got an address. + case "${_addr}" in + "") continue ;; + *) ;; + esac + + # Configure interface alias if requested by a given interface. + if [ -n "${_iface}" ]; then + case "${_action}" in + add) ifconfig ${_iface} ${_type} ${_addr}${_mask} alias + ;; + del) # When removing the IP, ignore the _mask. + ifconfig ${_iface} ${_type} ${_addr} -alias + ;; + esac + fi + + # Append address to list of addresses for the jail command. + case "${_addrl}" in + "") _addrl="${_addr}" ;; + *) _addrl="${_addrl},${_addr}" ;; + esac + done +} + +# jail_ips {add,del} +# Extract the comma separated list of addresses and return them +# for the jail command. +# Handle more than one address via the _multi option as well. +# If an interface is given also add/remove an alias for the +# address with an optional netmask. +# +jail_ips() +{ + local _action + _action=$1 + + case "${_action}" in + add) ;; + del) ;; + *) warn "jail_ips: invalid action '${_action}'" + return + ;; + esac + + # Handle addresses. + jail_handle_ips_option ${_action} "${_ip}" + # Handle jail_xxx_ip_multi + alias=0 + while : ; do + eval _x=\"\$jail_${_jail}_ip_multi${alias}\" + case "${_x}" in + "") break ;; + *) jail_handle_ips_option ${_action} "${_x}" + alias=$((${alias} + 1)) + ;; + esac + done +} + jail_start() { echo -n 'Configuring jails:' @@ -298,9 +487,8 @@ echo -n " [${_hostname} already running (/var/run/jail_${_jail}.id exists)]" continue; fi - if [ -n "${_interface}" ]; then - ifconfig ${_interface} alias ${_ip} netmask ${_netmask} - fi + _addrl="" + jail_ips "add" if [ -n "${_fib}" ]; then _setfib="setfib -F '${_fib}'" else @@ -360,7 +548,7 @@ fi _tmp_jail=${_tmp_dir}/jail.$$ eval ${_setfib} jail ${_flags} -i ${_rootdir} ${_hostname} \ - ${_ip} ${_exec_start} > ${_tmp_jail} 2>&1 + \"${_addrl}\" ${_exec_start} > ${_tmp_jail} 2>&1 if [ "$?" -eq 0 ] ; then _jail_id=$(head -1 ${_tmp_jail}) @@ -381,9 +569,7 @@ echo ${_jail_id} > /var/run/jail_${_jail}.id else jail_umount_fs - if [ -n "${_interface}" ]; then - ifconfig ${_interface} -alias ${_ip} - fi + jail_ips "del" echo " cannot start jail \"${_jail}\": " tail +2 ${_tmp_jail} fi @@ -412,9 +598,7 @@ jail_umount_fs echo -n " $_hostname" fi - if [ -n "${_interface}" ]; then - ifconfig ${_interface} -alias ${_ip} - fi + jail_ips "del" rm /var/run/jail_${_jail}.id else echo " cannot stop jail ${_jail}. No jail id in /var/run" Index: etc/defaults/rc.conf =================================================================== --- etc/defaults/rc.conf (revision 186887) +++ etc/defaults/rc.conf (working copy) @@ -617,14 +617,16 @@ # each jail, specified in jail_list, with the following variables. # NOTES: # - replace 'example' with the jail's name. -# - except rootdir, hostname and ip, all of the following variables may be made -# global jail variables if you don't specify a jail name (ie. jail_interface). +# - except rootdir, hostname, ip and the _multi addresses, +# all of the following variables may be made global jail variables +# if you don't specify a jail name (ie. jail_interface, jail_devfs_ruleset). # #jail_example_rootdir="/usr/jail/default" # Jail's root directory #jail_example_hostname="default.domain.com" # Jail's hostname -#jail_example_ip="192.0.2.10" # Jail's IP number -#jail_example_interface="" # Interface to create the IP alias on -#jail_example_fib="0" # routing table for setfib(1) +#jail_example_ip="192.0.2.10,2001:db8::17" # Jail's primary IPv4 and IPv6 address +#jail_example_ip_multi0="2001:db8::10" # and another IPv6 address +#jail_example_interface="" # Global interface variable to create IP aliases on +#jail_example_fib="0" # Routing table for setfib(1) #jail_example_exec_start="/bin/sh /etc/rc" # command to execute in jail for starting #jail_example_exec_afterstart0="/bin/sh command" # command to execute after the one for # starting the jail. More than one can be