Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 Jan 2009 12:59:11 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r187708 - in head: etc/defaults etc/rc.d share/man/man5
Message-ID:  <200901261259.n0QCxBMr050254@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Mon Jan 26 12:59:11 2009
New Revision: 187708
URL: http://svn.freebsd.org/changeset/base/187708

Log:
  Update jail startup script for multi-IPv4/v6/no-IP jails.
  
  Note: this is only really necessary because of the ifconfig
        logic to add/remove the jail IPs upon start/stop.
        Consensus among simon and I is that the logic should
        really be factored out from the startup script and put
        into a proper management solution.
  
  - We now support starting of no-IP jails.
  - Remove the global jail_<jname>_netmask option as it is only
    helpful to set netmasks/prefixes for the right address
    family and per address.
  - Implement jail_<jname>_ip options to support both
    address familes with regard to ifconfig logic.
  - Implement _multi<n> support suffix to the jail_<jname>_ip
    option to configure additional addresses to avoid overlong,
    unreadbale jail_<jname>_ip lines with lots of addresses.
  
  Submitted by:	initial work from Ruben van Staveren
  Discussed on:	freebsd-jail in Nov 2008.
  Reviewed by:	simon, ru (partial, older version)
  MFC after:	1 week

Modified:
  head/etc/defaults/rc.conf
  head/etc/rc.d/jail
  head/share/man/man5/rc.conf.5

Modified: head/etc/defaults/rc.conf
==============================================================================
--- head/etc/defaults/rc.conf	Mon Jan 26 07:31:28 2009	(r187707)
+++ head/etc/defaults/rc.conf	Mon Jan 26 12:59:11 2009	(r187708)
@@ -617,14 +617,16 @@ jail_sysvipc_allow="NO"	# Allow SystemV 
 # 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<n> 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_interface=""			# Jail's interface variable to create IP aliases 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_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

Modified: head/etc/rc.d/jail
==============================================================================
--- head/etc/rc.d/jail	Mon Jan 26 07:31:28 2009	(r187707)
+++ head/etc/rc.d/jail	Mon Jan 26 12:59:11 2009	(r187708)
@@ -39,7 +39,6 @@ init_variables()
 	_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 _exec=\"\$jail_${_j}_exec\"
 	eval _exec_start=\"\${jail_${_j}_exec_start:-${jail_exec_start}}\"
@@ -94,7 +93,7 @@ init_variables()
 	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 @@ init_variables()
 	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,208 @@ jail_mount_fstab()
 	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 interface is not set,
+	# as we only care about the _mask if we call ifconfig.
+	# This is not done because we may want to santize IP addresses
+	# based on _type later, and optionally change the type as well.
+
+	# 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" ;;
+	*)		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
+
+		# Append address to list of addresses for the jail command.
+		case "${_addrl}" in
+		"")	_addrl="${_addr}" ;;
+		*)	_addrl="${_addrl},${_addr}" ;;
+		esac
+
+		# Configure interface alias if requested by a given interface
+		# and if we could correctly parse everything.
+		case "${_iface}" in
+		"")	continue ;;
+		esac
+		case "${_type}" in
+		inet)	;;
+		inet6)	;;
+		*)	warn "Could not determine address family.  Not going" \
+			    "to ${_action} address '${_addr}' for ${_jail}."
+			continue
+			;;
+		esac
+		case "${_action}" in
+		add)	ifconfig ${_iface} ${_type} ${_addr}${_mask} alias
+			;;
+		del)	# When removing the IP, ignore the _mask.
+			ifconfig ${_iface} ${_type} ${_addr} -alias
+			;;
+		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<N>
+	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 +495,8 @@ jail_start()
 			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 +556,7 @@ jail_start()
 		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 +577,7 @@ jail_start()
 			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 +606,7 @@ jail_stop()
 				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"

Modified: head/share/man/man5/rc.conf.5
==============================================================================
--- head/share/man/man5/rc.conf.5	Mon Jan 26 07:31:28 2009	(r187707)
+++ head/share/man/man5/rc.conf.5	Mon Jan 26 12:59:11 2009	(r187708)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 24, 2009
+.Dd January 25, 2009
 .Dt RC.CONF 5
 .Os
 .Sh NAME
@@ -3426,8 +3426,38 @@ Set to the fully qualified domain name (
 .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 and/or IPv6 address(es) assigned to the jail.
+The argument can be a sole address or a comma separated list of addresses.
+Additionally each address can be prefixed by the name of an interface
+followed by a pipe to overwrite
+.Va jail_ Ns Ao Ar jname Ac Ns Va _interface
+or
+.Va jail_interface
+and/or suffixed by a netmask, prefixlen or prefix.
+In case no netmask, prefixlen or prefix is given,
+.Sq /32
+will be used for IPv4 and
+.Sq /128
+will be used for an IPv6 address.
+If no address is given for the jail then the jail will be started with
+no networking support.
+.It Va jail_ Ns Ao Ar jname Ac Ns Va _ip_multi Ns Aq Ar n
+.Pq Vt str
+Unset by default.
+Set additional IPv4 and/or IPv6 address(es) assigned to the jail.
+The sequence starts with
+.Dq Li _multi0
+and the numbers have to be strictly ascending.
+These entries follow the same syntax as their primary
+.Va jail_ Ns Ao Ar jname Ac Ns Va _ip
+entry.
+The order of the entries can be important as the first address for
+each address family found will be the primary address of the jail.
+See
+.Va ip-addresses
+option in
+.Xr jail 8
+for more details.
 .It Va jail_ Ns Ao Ar jname Ac Ns Va _flags
 .Pq Vt str
 Set to
@@ -3440,12 +3470,6 @@ These are flags to pass to
 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.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901261259.n0QCxBMr050254>