Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Aug 2011 10:47:12 -0700
From:      Devin Teske <devin.teske@fisglobal.com>
To:        FreeBSD Hackers <freebsd-hackers@freebsd.org>
Cc:        Julian Elischer <julian@freebsd.org>, FreeBSD Jail <freebsd-jail@freebsd.org>, FreeBSD RC <freebsd-rc@freebsd.org>, Dave Robison <daver@vicor.com>
Subject:   [PATCH] Add /etc/rc.d/vimage startup script for creating vnet jails
Message-ID:  <CAC979C8-3129-4E62-9D76-D1D0CCE001F0@fisglobal.com>

next in thread | raw e-mail | index | archive | help
--Apple-Mail-25--994899661
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="ISO-8859-1"

Hi All,

I'd like to submit a patch for review (attached) that adds a new /etc/rc.d =
script named "vimage".

_____________

The information contained in this message is proprietary and/or confidentia=
l. If you are not the intended recipient, please: (i) delete the message an=
d all copies; (ii) do not disclose, distribute or use the message in any ma=
nner; and (iii) notify the sender immediately. In addition, please be aware=
 that any message addressed to our domain is subject to archiving and revie=
w by persons other than the intended recipient. Thank you.
_____________

--Apple-Mail-25--994899661
Content-Disposition: attachment; filename="vimage_rc.20110827104104.patch"
Content-Type: application/octet-stream; name="vimage_rc.20110827104104.patch"
Content-Transfer-Encoding: 7bit

--- etc/defaults/rc.conf.orig	Fri Aug 26 20:36:52 2011
+++ etc/defaults/rc.conf	Sat Aug 27 10:34:54 2011
@@ -697,6 +697,43 @@
 #jail_example_flags="-l -U root"		# flags for jail(8)
 
 ##############################################################
+### Vimage Configuration #####################################
+##############################################################
+vimage_enable="NO"	# Set to NO to disable starting of any vimages
+vimage_parallel_start="NO"	# Start vimages in the background
+vimage_list=""		# Space separated list of names of vimages
+vimage_set_hostname_allow="YES" # Allow root user in a vimage to change its hostname
+vimage_socket_unixiproute_only="NO" # Route only TCP/IP within a vimage
+vimage_sysvipc_allow="YES"	# Allow SystemV IPC use from within a vimage
+
+#
+# To use rc's built-in vimage infrastructure create entries for
+# each vimage, specified in vimage_list, with the following variables.
+# NOTES:
+# - replace 'example' with the vimage's name.
+# - except rootdir, and hostname, all of the following variables may be made
+#   global vimage variables if you don't specify a vimage name (ie.
+#   vimage_fib, vimage_devfs_ruleset).
+#
+#vimage_example_rootdir="/usr/jail/default"	# Vimage's root directory
+#vimage_example_hostname="default.domain.com"	# Vimage's hostname
+#vimage_example_vnets="epair0b"			# Vimage's vnet interfaces
+#vimage_example_exec_start="/bin/sh /etc/rc"		# command to execute in vimage for starting
+#vimage_example_services="sshd ipfw zfs"		# services to start after starting vimage
+#vimage_example_exec_afterstart0="/bin/sh command"	# command to execute after the one for
+							# starting the vimage. More than one can
+							# be specified using a trailing number
+#vimage_example_exec_stop="/bin/sh /etc/rc.shutdown"	# command to execute in vimage for stopping
+#vimage_example_devfs_enable="NO"			# mount devfs in the vimage
+#vimage_example_devfs_ruleset="ruleset_name"	# devfs ruleset to apply to vimage -
+						# usually you want "devfsrules_jail".
+#vimage_example_fdescfs_enable="NO"		# mount fdescfs in the vimage
+#vimage_example_procfs_enable="NO"		# mount procfs in vimage
+#vimage_example_mount_enable="NO"			# mount/umount vimage's fs
+#vimage_example_fstab=""				# fstab(5) for mount/umount
+#vimage_example_flags="-l -U root"		# flags for jail(8)
+
+##############################################################
 ### Define source_rc_confs, the mechanism used by /etc/rc.* ##
 ### scripts to source rc_conf_files overrides safely.	    ##
 ##############################################################
--- etc/rc.d/vimage.orig	Sat Aug 27 10:26:53 2011
+++ etc/rc.d/vimage	Sat Aug 27 10:36:03 2011
@@ -0,0 +1,551 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: vimage
+# REQUIRE: LOGIN cleanvar
+# BEFORE: securelevel
+# KEYWORD: nojail shutdown
+
+# WARNING: This script deals with untrusted data (the data and
+# processes inside the vimage) and care must be taken when changing the
+# code related to this!  If you have any doubt whether a change is
+# correct and have security impact, please get the patch reviewed by
+# the FreeBSD Security Team prior to commit.
+
+. /etc/rc.subr
+
+name="vimage"
+rcvar=`set_rcvar`
+
+start_precmd="vimage_prestart"
+start_cmd="vimage_start"
+stop_cmd="vimage_stop"
+
+# init_variables _v
+#	Initialize the various vimage variables for vimage _v.
+#
+init_variables()
+{
+	_v="$1"
+
+	if [ -z "$_v" ]; then
+		warn "init_variables: you must specify a vimage"
+		return
+	fi
+
+	eval _rootdir=\"\$vimage_${_v}_rootdir\"
+	_devdir="${_rootdir}/dev"
+	_fdescdir="${_devdir}/fd"
+	_procdir="${_rootdir}/proc"
+	eval _hostname=\"\$vimage_${_v}_hostname\"
+	eval _vnets=\"\$vimage_${_v}_vnets\"
+	eval _exec=\"\$vimage_${_v}_exec\"
+
+	i=0
+	while : ; do
+		eval _exec_prestart${i}=\"\${vimage_${_v}_exec_prestart${i}:-\${vimage_exec_prestart${i}}}\"
+		[ -z "$(eval echo \"\$_exec_prestart${i}\")" ] && break
+		i=$((i + 1))
+	done
+
+	eval _exec_start=\"\${vimage_${_v}_exec_start:-${vimage_exec_start}}\"
+	eval _services=\"\${vimage_${_v}_services:-${vimage_services}}\"
+
+	i=1
+	while : ; do
+		eval _exec_afterstart${i}=\"\${vimage_${_v}_exec_afterstart${i}:-\${vimage_exec_afterstart${i}}}\"
+		[ -z "$(eval echo \"\$_exec_afterstart${i}\")" ] &&  break
+		i=$((i + 1))
+	done
+
+	i=0
+	while : ; do
+		eval _exec_poststart${i}=\"\${vimage_${_v}_exec_poststart${i}:-\${vimage_exec_poststart${i}}}\"
+		[ -z "$(eval echo \"\$_exec_poststart${i}\")" ] && break
+		i=$((i + 1))
+	done
+
+	i=0
+	while : ; do
+		eval _exec_prestop${i}=\"\${vimage_${_v}_exec_prestop${i}:-\${vimage_exec_prestop${i}}}\"
+		[ -z "$(eval echo \"\$_exec_prestop${i}\")" ] && break
+		i=$((i + 1))
+	done
+
+	eval _exec_stop=\"\${vimage_${_v}_exec_stop:-${vimage_exec_stop}}\"
+
+	i=0
+	while : ; do
+		eval _exec_poststop${i}=\"\${vimage_${_v}_exec_poststop${i}:-\${vimage_exec_poststop${i}}}\"
+		[ -z "$(eval echo \"\$_exec_poststop${i}\")" ] && break
+		i=$((i + 1))
+	done
+
+	if [ -n "${_exec}" ]; then
+		#   simple/backward-compatible execution
+		_exec_start="${_exec}"
+		_exec_stop=""
+	else
+		#   flexible execution
+		if [ -z "${_exec_start}" ]; then
+			_exec_start="/bin/sh /etc/rc"
+			if [ -z "${_exec_stop}" ]; then
+				_exec_stop="/bin/sh /etc/rc.shutdown"
+			fi
+		fi
+	fi
+
+	# The default jail ruleset will be used by rc.subr if none is specified.
+	eval _ruleset=\"\${vimage_${_v}_devfs_ruleset:-${vimage_devfs_ruleset}}\"
+	eval _devfs=\"\${vimage_${_v}_devfs_enable:-${vimage_devfs_enable}}\"
+	[ -z "${_devfs}" ] && _devfs="NO"
+	eval _fdescfs=\"\${vimage_${_v}_fdescfs_enable:-${vimage_fdescfs_enable}}\"
+	[ -z "${_fdescfs}" ] && _fdescfs="NO"
+	eval _procfs=\"\${vimage_${_v}_procfs_enable:-${vimage_procfs_enable}}\"
+	[ -z "${_procfs}" ] && _procfs="NO"
+
+	eval _mount=\"\${vimage_${_v}_mount_enable:-${vimage_mount_enable}}\"
+	[ -z "${_mount}" ] && _mount="NO"
+	# "/etc/fstab.${_v}" will be used for {,u}mount(8) if none is specified.
+	eval _fstab=\"\${vimage_${_v}_fstab:-${vimage_fstab}}\"
+	[ -z "${_fstab}" ] && _fstab="/etc/fstab.${_v}"
+	eval _flags=\"\${vimage_${_v}_flags:-${vimage_flags}}\"
+	[ -z "${_flags}" ] && _flags="-l -U root"
+	eval _consolelog=\"\${vimage_${_v}_consolelog:-${vimage_consolelog}}\"
+	[ -z "${_consolelog}" ] && _consolelog="/var/log/vimage_${_v}_console.log"
+
+	# Debugging aid
+	#
+	debug "$_v devfs enable: $_devfs"
+	debug "$_v fdescfs enable: $_fdescfs"
+	debug "$_v procfs enable: $_procfs"
+	debug "$_v mount enable: $_mount"
+	debug "$_v hostname: $_hostname"
+	debug "$_v vnets: $_vnets"
+	debug "$_v services: $_services"
+	debug "$_v root: $_rootdir"
+	debug "$_v devdir: $_devdir"
+	debug "$_v fdescdir: $_fdescdir"
+	debug "$_v procdir: $_procdir"
+	debug "$_v ruleset: $_ruleset"
+	debug "$_v fstab: $_fstab"
+
+	i=0
+	while : ; do
+		eval out=\"\${_exec_prestart${i}:-''}\"
+		if [ -z "$out" ]; then
+			break
+		fi
+		debug "$_v exec pre-start #${i}: ${out}"
+		i=$((i + 1))
+	done
+
+	debug "$_v exec start: $_exec_start"
+
+	i=1
+	while : ; do
+		eval out=\"\${_exec_afterstart${i}:-''}\"
+
+		if [ -z "$out" ]; then
+			break;
+		fi
+
+		debug "$_v exec after start #${i}: ${out}"
+		i=$((i + 1))
+	done
+
+	i=0
+	while : ; do
+		eval out=\"\${_exec_poststart${i}:-''}\"
+		if [ -z "$out" ]; then
+			break
+		fi
+		debug "$_v exec post-start #${i}: ${out}"
+		i=$((i + 1))
+	done
+
+	i=0
+	while : ; do
+		eval out=\"\${_exec_prestop${i}:-''}\"
+		if [ -z "$out" ]; then
+			break
+		fi
+		debug "$_v exec pre-stop #${i}: ${out}"
+		i=$((i + 1))
+	done
+
+	debug "$_v exec stop: $_exec_stop"
+
+	i=0
+	while : ; do
+		eval out=\"\${_exec_poststop${i}:-''}\"
+		if [ -z "$out" ]; then
+			break
+		fi
+		debug "$_v exec post-stop #${i}: ${out}"
+		i=$((i + 1))
+	done
+
+	debug "$_v flags: $_flags"
+	debug "$_v consolelog: $_consolelog"
+
+	if [ -z "${_hostname}" ]; then
+		err 3 "$name: No hostname has been defined for ${_v}"
+	fi
+	if [ -z "${_rootdir}" ]; then
+		err 3 "$name: No root directory has been defined for ${_v}"
+	fi
+}
+
+# set_sysctl rc_knob mib msg
+#	If the mib sysctl is set according to what rc_knob
+#	specifies, this function does nothing. However if
+#	rc_knob is set differently than mib, then the mib
+#	is set accordingly and msg is displayed followed by
+#	an '=" sign and the word 'YES' or 'NO'.
+#
+set_sysctl()
+{
+	_knob="$1"
+	_mib="$2"
+	_msg="$3"
+
+	_current=`${SYSCTL} -n $_mib 2>/dev/null`
+	if checkyesno $_knob ; then
+		if [ "$_current" -ne 1 ]; then
+			echo -n " ${_msg}=YES"
+			${SYSCTL} 1>/dev/null ${_mib}=1
+		fi
+	else
+		if [ "$_current" -ne 0 ]; then
+			echo -n " ${_msg}=NO"
+			${SYSCTL} 1>/dev/null ${_mib}=0
+		fi
+	fi
+}
+
+# is_current_mountpoint()
+#	Is the directory mount point for a currently mounted file
+#	system?
+#
+is_current_mountpoint()
+{
+	local _dir _dir2
+
+	_dir=$1
+
+	_dir=`echo $_dir | sed -Ee 's#//+#/#g' -e 's#/$##'`
+	[ ! -d "${_dir}" ] && return 1
+	_dir2=`df ${_dir} | tail +2 | awk '{ print $6 }'`
+	[ "${_dir}" = "${_dir2}" ]
+	return $?
+}
+
+# is_symlinked_mountpoint()
+#	Is a mount point, or any of its parent directories, a symlink?
+#
+is_symlinked_mountpoint()
+{
+	local _dir
+
+	_dir=$1
+
+	[ -L "$_dir" ] && return 0
+	[ "$_dir" = "/" ] && return 1
+	is_symlinked_mountpoint `dirname $_dir`
+	return $?
+}
+
+# secure_umount
+#	Try to unmount a mount point without being vulnerable to
+#	symlink attacks.
+#
+secure_umount()
+{
+	local _dir
+
+	_dir=$1
+
+	if is_current_mountpoint ${_dir}; then
+		umount -f ${_dir} >/dev/null 2>&1
+	else
+		debug "Nothing mounted on ${_dir} - not unmounting"
+	fi
+}
+
+
+# vimage_umount_fs
+#	This function unmounts certain special filesystems in the
+#	currently selected vimage. The caller must call the init_variables()
+#	routine before calling this one.
+#
+vimage_umount_fs()
+{
+	local _device _mountpt _rest
+
+	if checkyesno _fdescfs; then
+		if [ -d "${_fdescdir}" ] ; then
+			secure_umount ${_fdescdir}
+		fi
+	fi
+	if checkyesno _devfs; then
+		if [ -d "${_devdir}" ] ; then
+			secure_umount ${_devdir}
+		fi
+	fi
+	if checkyesno _procfs; then
+		if [ -d "${_procdir}" ] ; then
+			secure_umount ${_procdir}
+		fi
+	fi
+	if checkyesno _mount; then
+		[ -f "${_fstab}" ] || warn "${_fstab} does not exist"
+		tail -r ${_fstab} | while read _device _mountpt _rest; do
+			case ":${_device}" in
+			:#* | :)
+				continue
+				;;
+			esac
+			secure_umount ${_mountpt}
+		done
+	fi
+}
+
+# vimage_mount_fstab()
+#	Mount file systems from a per vimage fstab while trying to
+#	secure against symlink attacks at the mount points.
+#
+#	If we are certain we cannot secure against symlink attacks we
+#	do not mount all of the file systems (since we cannot just not
+#	mount the file system with the problematic mount point).
+#
+#	The caller must call the init_variables() routine before
+#	calling this one.
+#
+vimage_mount_fstab()
+{
+	local _device _mountpt _rest
+
+	while read _device _mountpt _rest; do
+		case ":${_device}" in
+		:#* | :)
+			continue
+			;;
+		esac
+		if is_symlinked_mountpoint ${_mountpt}; then
+			warn "${_mountpt} has symlink as parent - not mounting from ${_fstab}"
+			return
+		fi
+	done <${_fstab}
+	mount -a -F "${_fstab}"
+}
+
+vimage_prestart()
+{
+	if checkyesno vimage_parallel_start; then
+		command_args="&"
+	fi
+}
+
+vimage_start()
+{
+	echo -n 'Configuring vimages:'
+	set_sysctl vimage_set_hostname_allow \
+		security.jail.set_hostname_allowed \
+		set_hostname_allow
+	set_sysctl vimage_socket_unixiproute_only \
+	    security.jail.socket_unixiproute_only unixiproute_only
+	set_sysctl vimage_sysvipc_allow security.jail.sysvipc_allowed \
+	    sysvipc_allow
+	echo '.'
+
+	echo -n 'Starting vimages:'
+	_tmp_dir=`mktemp -d /tmp/vimage.XXXXXXXX` || \
+	    err 3 "$name: Can't create temp dir, exiting..."
+	for _vimage in ${vimage_list}
+	do
+		init_variables $_vimage
+		if [ -f /var/run/vimage_${_vimage}.id ]; then
+			echo -n " [${_hostname} already running (/var/run/vimage_${_vimage}.id exists)]"
+			continue;
+		fi
+		if checkyesno _mount; then
+			info "Mounting fstab for vimage ${_vimage} (${_fstab})"
+			if [ ! -f "${_fstab}" ]; then
+				err 3 "$name: ${_fstab} does not exist"
+			fi
+			vimage_mount_fstab
+		fi
+		if checkyesno _devfs; then
+			# If devfs is already mounted here, skip it.
+			df -t devfs "${_devdir}" >/dev/null
+			if [ $? -ne 0 ]; then
+				if is_symlinked_mountpoint ${_devdir}; then
+					warn "${_devdir} has symlink as parent - not starting vimage ${_vimage}"
+					continue
+				fi
+				info "Mounting devfs on ${_devdir}"
+				devfs_mount_jail "${_devdir}" ${_ruleset}
+				# Transitional symlink for old binaries
+				if [ ! -L "${_devdir}/log" ]; then
+					__pwd="`pwd`"
+					cd "${_devdir}"
+					ln -sf ../var/run/log log
+					cd "$__pwd"
+				fi
+			fi
+
+			# XXX - It seems symlinks don't work when there
+			#	is a devfs(5) device of the same name.
+			# Jail console output
+			#	__pwd="`pwd`"
+			#	cd "${_devdir}"
+			#	ln -sf ../var/log/console console
+			#	cd "$__pwd"
+		fi
+		if checkyesno _fdescfs; then
+			if is_symlinked_mountpoint ${_fdescdir}; then
+				warn "${_fdescdir} has symlink as parent, not mounting"
+			else
+				info "Mounting fdescfs on ${_fdescdir}"
+				mount -t fdescfs fdesc "${_fdescdir}"
+			fi
+		fi
+		if checkyesno _procfs; then
+			if is_symlinked_mountpoint ${_procdir}; then
+				warn "${_procdir} has symlink as parent, not mounting"
+			else
+				info "Mounting procfs onto ${_procdir}"
+				if [ -d "${_procdir}" ] ; then
+					mount -t procfs proc "${_procdir}"
+				fi
+			fi
+		fi
+		_tmp_vimage=${_tmp_dir}/vimage.$$
+
+		i=0
+		while : ; do
+			eval out=\"\${_exec_prestart${i}:-''}\"
+			[ -z "$out" ] && break
+			${out}
+			i=$((i + 1))
+		done
+
+		eval jail ${_flags} -i -c vnet name=\"${_vimage}\" \
+			host.hostname=\"${_hostname}\" \
+			path=\"${_rootdir}\" persist > ${_tmp_vimage} 2>&1
+
+		if [ "$?" -eq 0 ] ; then
+			_vimage_id=$(head -1 ${_tmp_vimage})
+
+			for _vnet in ${_vnets}; do
+				ifconfig ${_vnet} vnet "${_vimage_id}" \
+					> /dev/null 2>&1
+
+				case ${_vnet} in
+				epair[0-9]*[ab])
+					ifconfig ${_vnet%?}a up \
+						> /dev/null 2>&1;;
+				esac
+			done
+
+			eval jexec \"${_vimage_id}\" \
+				${_exec_start} >> ${_tmp_vimage} 2>&1
+
+			for _service in netif routing ${_services}; do
+				eval jexec \"${_vimage_id}\" /bin/sh \
+					/usr/sbin/service ${_service} start \
+					>> ${_tmp_vimage} 2>&1
+			done
+
+			i=1
+			while : ; do
+				eval out=\"\${_exec_afterstart${i}:-''}\"
+
+				if [ -z "$out" ]; then
+					break;
+				fi
+
+				jexec "${_vimage_id}" ${out}
+				i=$((i + 1))
+			done
+
+			echo -n " $_hostname"
+			tail +2 ${_tmp_vimage} >${_consolelog}
+			echo ${_vimage_id} > /var/run/vimage_${_vimage}.id
+
+			i=0
+			while : ; do
+				eval out=\"\${_exec_poststart${i}:-''}\"
+				[ -z "$out" ] && break
+				${out}
+				i=$((i + 1))
+			done
+		else
+			vimage_umount_fs
+			echo " cannot start vimage \"${_vimage}\": "
+			tail +2 ${_tmp_vimage}
+		fi
+		rm -f ${_tmp_vimage}
+	done
+	rmdir ${_tmp_dir}
+	echo '.'
+}
+
+vimage_stop()
+{
+	echo -n 'Stopping vimages:'
+	for _vimage in ${vimage_list}
+	do
+		if [ -f "/var/run/vimage_${_vimage}.id" ]; then
+			_vimage_id=$(cat /var/run/vimage_${_vimage}.id)
+			if [ ! -z "${_vimage_id}" ]; then
+				init_variables $_vimage
+
+				i=0
+				while : ; do
+					eval out=\"\${_exec_prestop${i}:-''}\"
+					[ -z "$out" ] && break
+					${out}
+					i=$((i + 1))
+				done
+
+				if [ -n "${_exec_stop}" ]; then
+					eval env -i /usr/sbin/jexec ${_vimage_id} ${_exec_stop} \
+						>> ${_consolelog} 2>&1
+				fi
+				killall -j ${_vimage_id} -TERM > /dev/null 2>&1
+				sleep 1
+				killall -j ${_vimage_id} -KILL > /dev/null 2>&1
+				vimage_umount_fs
+				echo -n " $_hostname"
+
+				i=0
+				while : ; do
+					eval out=\"\${_exec_poststop${i}:-''}\"
+					[ -z "$out" ] && break
+					${out}
+					i=$((i + 1))
+				done
+			fi
+			rm /var/run/vimage_${_vimage}.id
+			jail -r ${_vimage}
+		else
+			echo " cannot stop vimage ${_vimage}. No vimage id in /var/run"
+		fi
+	done
+	echo '.'
+}
+
+load_rc_config $name
+cmd="$1"
+if [ $# -gt 0 ]; then
+	shift
+fi
+if [ -n "$*" ]; then
+	vimage_list="$*"
+fi
+
+run_rc_command "${cmd}"

--Apple-Mail-25--994899661
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="us-ascii"



Essentially, a hand-tweaked version of /etc/rc.d/jail with added/removed =
features.

Here's how we're using it in /etc/rc.conf to successfully start up =
vimage jails at boot time:

=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D BEGIN EXCERPT =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

#
# Vimages
#
vimage_enable=3D"YES"     # Set to NO to disable starting of any vimages
vimage_list=3D"
        vnettest
" # Space-separated list of names of vimages
clone_interfaces=3D""     # Initialize list of epair/bridge interfaces =
to create

#
# Global settings for all Vimages
#
vimage_services=3D"sshd"

####################### VIMAGE: vnettest
cloned_interfaces=3D"$cloned_interfaces epair0 bridge0"
ifconfig_bridge0=3D"addm fxp0 addm epair0a"
vimage_vnettest_rootdir=3D"/usr/jails/vnettest"           # root =
directory
vimage_vnettest_hostname=3D"vnettest.jbsd.vicor.com"      # hostname
vimage_vnettest_devfs_enable=3D"YES"                      # mount devfs
vimage_vnettest_vnets=3D"epair0b"                         # network =
interfaces

####################### VIMAGE: {name}
#cloned_interfaces=3D"$cloned_interfaces epair{N} bridge{N}"
#ifconfig_bridge{N}=3D"addm {iface} addm epair{N}a"
#vimage_{name}_rootdir=3D"/usr/jails/{name}"              # root =
directory
#vimage_{name}_hostname=3D"{hostname}"                    # hostname
#vimage_{name}_devfs_enable=3D"YES"                       # mount devfs
#vimage_{name}_vnets=3D"epair{N}b"                        # network =
interfaces
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D END EXCERPT =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

--=20
Cheers,
Devin=

--Apple-Mail-25--994899661--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAC979C8-3129-4E62-9D76-D1D0CCE001F0>