1247280Sdteskeif [ ! "$_MEDIA_TCPIP_SUBR" ]; then _MEDIA_TCPIP_SUBR=1
2247280Sdteske#
3247280Sdteske# Copyright (c) 2012-2013 Devin Teske
4252980Sdteske# All rights reserved.
5247280Sdteske#
6247280Sdteske# Redistribution and use in source and binary forms, with or without
7247280Sdteske# modification, are permitted provided that the following conditions
8247280Sdteske# are met:
9247280Sdteske# 1. Redistributions of source code must retain the above copyright
10247280Sdteske#    notice, this list of conditions and the following disclaimer.
11247280Sdteske# 2. Redistributions in binary form must reproduce the above copyright
12247280Sdteske#    notice, this list of conditions and the following disclaimer in the
13247280Sdteske#    documentation and/or other materials provided with the distribution.
14247280Sdteske#
15247280Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16252987Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17247280Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18247280Sdteske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19247280Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20252987Sdteske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21247280Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22247280Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23247280Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24247280Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25247280Sdteske# SUCH DAMAGE.
26247280Sdteske#
27247280Sdteske# $FreeBSD: releng/10.3/usr.sbin/bsdconfig/share/media/tcpip.subr 266290 2014-05-17 03:28:43Z dteske $
28247280Sdteske#
29247280Sdteske############################################################ INCLUDES
30247280Sdteske
31247280SdteskeBSDCFG_SHARE="/usr/share/bsdconfig"
32247280Sdteske. $BSDCFG_SHARE/common.subr || exit 1
33247280Sdteskef_dprintf "%s: loading includes..." media/tcpip.subr
34247280Sdteskef_include $BSDCFG_SHARE/device.subr
35247280Sdteskef_include $BSDCFG_SHARE/dialog.subr
36260678Sdteskef_include $BSDCFG_SHARE/strings.subr
37252077Sdteskef_include $BSDCFG_SHARE/struct.subr
38247280Sdteskef_include $BSDCFG_SHARE/variable.subr
39247280Sdteske
40247280SdteskeBSDCFG_LIBE="/usr/libexec/bsdconfig"
41247280Sdteskef_include_lang $BSDCFG_LIBE/include/messages.subr
42247280Sdteske
43247280SdteskeTCP_HELPFILE=$BSDCFG_LIBE/include/tcp.hlp
44247280SdteskeNETWORK_DEVICE_HELPFILE=$BSDCFG_LIBE/include/network_device.hlp
45247280Sdteske
46247280Sdteske############################################################ GLOBALS
47247280Sdteske
48247280Sdteske#
49247280Sdteske# Path to resolv.conf(5).
50247280Sdteske#
51247280Sdteske: ${RESOLV_CONF:="/etc/resolv.conf"}
52247280Sdteske
53247280Sdteske#
54247280Sdteske# Path to nsswitch.conf(5).
55247280Sdteske#
56247280Sdteske: ${NSSWITCH_CONF:="/etc/nsswitch.conf"}
57247280Sdteske
58247280Sdteske#
59247280Sdteske# Path to hosts(5)
60247280Sdteske#
61247280Sdteske: ${ETC_HOSTS:="/etc/hosts"}
62247280Sdteske
63247280Sdteske#
64247280Sdteske# Structure of dhclient.leases(5) lease { ... } entry
65247280Sdteske#
66247280Sdteskef_struct_define DHCP_LEASE \
67247280Sdteske	interface		\
68247280Sdteske	fixed_address		\
69247280Sdteske	filename		\
70247280Sdteske	server_name		\
71247280Sdteske	script			\
72247280Sdteske	medium			\
73247280Sdteske	host_name		\
74247280Sdteske	subnet_mask		\
75247280Sdteske	routers			\
76247280Sdteske	domain_name_servers	\
77247280Sdteske	domain_name		\
78247280Sdteske	broadcast_address	\
79247280Sdteske	dhcp_lease_time		\
80247280Sdteske	dhcp_message_type	\
81247280Sdteske	dhcp_server_identifier	\
82247280Sdteske	dhcp_renewal_time	\
83247280Sdteske	dhcp_rebinding_time	\
84247280Sdteske	renew			\
85247280Sdteske	rebind			\
86247280Sdteske	expire
87247280Sdteske
88247280Sdteske############################################################ FUNCTIONS
89247280Sdteske
90247280Sdteske# f_validate_hostname $hostname
91247280Sdteske#
92247280Sdteske# Returns zero if the given argument (a fully-qualified hostname) is compliant
93247280Sdteske# with standards set-forth in RFC's 952 and 1123 of the Network Working Group:
94247280Sdteske#
95247280Sdteske# RFC 952 - DoD Internet host table specification
96247280Sdteske# http://tools.ietf.org/html/rfc952
97247280Sdteske#
98247280Sdteske# RFC 1123 - Requirements for Internet Hosts - Application and Support
99247280Sdteske# http://tools.ietf.org/html/rfc1123
100247280Sdteske#
101247280Sdteske# See http://en.wikipedia.org/wiki/Hostname for a brief overview.
102247280Sdteske#
103247280Sdteske# The return status for invalid hostnames is one of:
104247280Sdteske# 	255	Entire hostname exceeds the maximum length of 255 characters.
105247280Sdteske# 	 63	One or more individual labels within the hostname (separated by
106247280Sdteske# 	   	dots) exceeds the maximum of 63 characters.
107247280Sdteske# 	  1	One or more individual labels within the hostname contains one
108247280Sdteske# 	   	or more invalid characters.
109247280Sdteske# 	  2	One or more individual labels within the hostname starts or
110247280Sdteske# 	   	ends with a hyphen (hyphens are allowed, but a label cannot
111247280Sdteske# 	   	begin or end with a hyphen).
112247280Sdteske# 	  3	One or more individual labels within the hostname are null.
113247280Sdteske#
114260675Sdteske# To call this function and display an appropriate error message to the user
115260675Sdteske# based on the above error codes, use the following function defined in
116260675Sdteske# dialog.subr:
117247280Sdteske#
118260675Sdteske# 	f_dialog_validate_hostname $hostname
119247280Sdteske#
120247280Sdteskef_validate_hostname()
121247280Sdteske{
122247280Sdteske	local fqhn="$1"
123247280Sdteske
124247280Sdteske	# Return error if the hostname exceeds 255 characters
125247280Sdteske	[ ${#fqhn} -gt 255 ] && return 255
126247280Sdteske
127247280Sdteske	local IFS="." # Split on `dot'
128247280Sdteske	for label in $fqhn; do
129247280Sdteske		# Return error if the label exceeds 63 characters
130247280Sdteske		[ ${#label} -gt 63 ] && return 63
131247280Sdteske
132247280Sdteske		# Return error if the label is null
133247280Sdteske		[ "$label" ] || return 3
134247280Sdteske
135247280Sdteske		# Return error if label begins/ends with dash
136247280Sdteske		case "$label" in -*|*-) return 2; esac
137247280Sdteske
138247280Sdteske		# Return error if the label contains any invalid chars
139247280Sdteske		case "$label" in *[!0-9a-zA-Z-]*) return 1; esac
140247280Sdteske	done
141247280Sdteske
142247280Sdteske	return $SUCCESS
143247280Sdteske}
144247280Sdteske
145247280Sdteske# f_inet_atoi $ipv4_address [$var_to_set]
146247280Sdteske#
147247280Sdteske# Convert an IPv4 address or mask from dotted-quad notation (e.g., `127.0.0.1'
148247280Sdteske# or `255.255.255.0') to a 32-bit unsigned integer for the purpose of network
149247280Sdteske# and broadcast calculations. For example, one can validate that two addresses
150247280Sdteske# are on the same network:
151247280Sdteske#
152247280Sdteske# 	f_inet_atoi 1.2.3.4 ip1num
153247280Sdteske# 	f_inet_atoi 1.2.4.5 ip2num
154247280Sdteske# 	f_inet_atoi 255.255.0.0 masknum
155247280Sdteske# 	if [ $(( $ip1num & $masknum )) -eq \
156247280Sdteske# 	     $(( $ip2num & $masknum )) ]
157247280Sdteske# 	then
158247280Sdteske# 		: IP addresses are on same network
159247280Sdteske# 	fi
160247280Sdteske#
161247280Sdteske# See f_validate_ipaddr() below for an additional example usage, on calculating
162247280Sdteske# network and broadcast addresses.
163247280Sdteske#
164247280Sdteske# If $var_to_set is missing or NULL, the converted IP address is printed to
165247280Sdteske# standard output for capturing in a sub-shell (which is less-recommended
166247280Sdteske# because of performance degredation; for example, when called in a loop).
167247280Sdteske#
168247280Sdteskef_inet_atoi()
169247280Sdteske{
170247280Sdteske	local __addr="$1" __var_to_set="$2" __num=0
171247280Sdteske	if f_validate_ipaddr "$__addr"; then
172266290Sdteske		local IFS=.
173260678Sdteske		set -- $__addr
174260678Sdteske		__num=$(( ($1 << 24) + ($2 << 16) + ($3 << 8) + $4 ))
175247280Sdteske	fi
176247280Sdteske	if [ "$__var_to_set" ]; then
177247280Sdteske		setvar "$__var_to_set" $__num
178247280Sdteske	else
179247280Sdteske		echo $__num
180247280Sdteske	fi
181247280Sdteske}
182247280Sdteske
183247280Sdteske# f_validate_ipaddr $ipaddr [$netmask]
184247280Sdteske#
185247280Sdteske# Returns zero if the given argument (an IP address) is of the proper format.
186247280Sdteske#
187247280Sdteske# The return status for invalid IP address is one of:
188247280Sdteske# 	1	One or more individual octets within the IP address (separated
189247280Sdteske# 	 	by dots) contains one or more invalid characters.
190247280Sdteske# 	2	One or more individual octets within the IP address are null
191247280Sdteske# 	 	and/or missing.
192247280Sdteske# 	3	One or more individual octets within the IP address exceeds the
193247280Sdteske# 	 	maximum of 255 (or 2^8, being an octet comprised of 8 bits).
194247280Sdteske# 	4	The IP address has either too few or too many octets.
195247280Sdteske#
196247280Sdteske# If a netmask is provided, the IP address is checked further:
197247280Sdteske#
198247280Sdteske# 	5	The IP address must not be the network or broadcast address.
199247280Sdteske#
200247280Sdteskef_validate_ipaddr()
201247280Sdteske{
202247280Sdteske	local ip="$1" mask="$2"
203247280Sdteske
204247280Sdteske	# Track number of octets for error checking
205247280Sdteske	local noctets=0
206247280Sdteske
207266290Sdteske	local oldIFS="$IFS" IFS="." # Split on `dot'
208247280Sdteske	for octet in $ip; do
209247280Sdteske		# Return error if the octet is null
210247280Sdteske		[ "$octet" ] || return 2
211247280Sdteske
212247280Sdteske		# Return error if not a whole integer
213247280Sdteske		f_isinteger "$octet" || return 1
214247280Sdteske
215247280Sdteske		# Return error if not a positive integer
216247280Sdteske		[ $octet -ge 0 ] || return 1
217247280Sdteske
218247280Sdteske		# Return error if the octet exceeds 255
219247280Sdteske		[ $octet -gt 255 ] && return 3
220247280Sdteske
221247280Sdteske		noctets=$(( $noctets + 1 ))
222247280Sdteske	done
223247280Sdteske	IFS="$oldIFS"
224247280Sdteske
225247280Sdteske	[ $noctets -eq 4 ] || return 4
226247280Sdteske
227247280Sdteske	#
228247280Sdteske	# The IP address must not be network or broadcast address.
229247280Sdteske	#
230247280Sdteske	if [ "$mask" ]; then
231247280Sdteske		local ipnum masknum netnum bcastnum
232247280Sdteske		local max_addr=4294967295 # 255.255.255.255
233247280Sdteske
234247280Sdteske		f_inet_atoi $ip ipnum
235247280Sdteske		f_inet_atoi $mask masknum
236247280Sdteske
237247280Sdteske		netnum=$(( $ipnum & $masknum ))
238247280Sdteske		bcastnum=$(( ($ipnum & $masknum)+$max_addr-$masknum ))
239247280Sdteske
240247280Sdteske		if [ "$masknum" ] &&
241247280Sdteske		   [ $ipnum -eq $netnum -o $ipnum -eq $bcastnum ]
242247280Sdteske		then
243247280Sdteske			return 5
244247280Sdteske		fi
245247280Sdteske	fi
246247280Sdteske
247247280Sdteske	return $SUCCESS
248247280Sdteske}
249247280Sdteske
250247280Sdteske# f_validate_ipaddr6 $ipv6_addr
251247280Sdteske#
252247280Sdteske# Returns zero if the given argument (an IPv6 address) is of the proper format.
253247280Sdteske#
254247280Sdteske# The return status for invalid IP address is one of:
255247280Sdteske# 	1	One or more individual segments within the IP address
256247280Sdteske# 	 	(separated by colons) contains one or more invalid characters.
257247280Sdteske# 	 	Segments must contain only combinations of the characters 0-9,
258247280Sdteske# 	 	A-F, or a-f.
259247280Sdteske# 	2	Too many/incorrect null segments. A single null segment is
260247280Sdteske# 	 	allowed within the IP address (separated by colons) but not
261247280Sdteske# 	 	allowed at the beginning or end (unless a double-null segment;
262247280Sdteske# 	 	i.e., "::*" or "*::").
263247280Sdteske# 	3	One or more individual segments within the IP address
264247280Sdteske# 	 	(separated by colons) exceeds the length of 4 hex-digits.
265247280Sdteske# 	4	The IP address entered has either too few (less than 3), too
266247280Sdteske# 	 	many (more than 8), or not enough segments, separated by
267247280Sdteske# 	 	colons.
268247280Sdteske# 	5*	The IPv4 address at the end of the IPv6 address is invalid.
269247280Sdteske# 	*	When there is an error with the dotted-quad IPv4 address at the
270247280Sdteske# 	 	end of the IPv6 address, the return value of 5 is OR'd with a
271247280Sdteske# 	 	bit-shifted (<< 4) return of f_validate_ipaddr.
272247280Sdteske#
273247280Sdteskef_validate_ipaddr6()
274247280Sdteske{
275247280Sdteske	local ip="${1%\%*}" # removing the interface specification if-present
276247280Sdteske
277247280Sdteske	local IFS=":" # Split on `colon'
278247280Sdteske	set -- $ip:
279247280Sdteske
280247280Sdteske	# Return error if too many or too few segments
281247280Sdteske	# Using 9 as max in case of leading or trailing null spanner
282247280Sdteske	[ $# -gt 9 -o $# -lt 3 ] && return 4
283247280Sdteske
284247280Sdteske	local h="[0-9A-Fa-f]"
285247280Sdteske	local nulls=0 nsegments=$# contains_ipv4_segment=
286247280Sdteske
287247280Sdteske	while [ $# -gt 0 ]; do
288247280Sdteske
289247280Sdteske		segment="${1%:}"
290247280Sdteske		shift
291247280Sdteske
292247280Sdteske		#
293247280Sdteske		# Return error if this segment makes one null too-many. A
294247280Sdteske		# single null segment is allowed anywhere in the middle as well
295247280Sdteske		# as double null segments are allowed at the beginning or end
296247280Sdteske		# (but not both).
297247280Sdteske		#
298247280Sdteske		if [ ! "$segment" ]; then
299247280Sdteske			nulls=$(( $nulls + 1 ))
300247280Sdteske			if [ $nulls -eq 3 ]; then
301247280Sdteske				# Only valid syntax for 3 nulls is `::'
302247280Sdteske				[ "$ip" = "::" ] || return 2
303247280Sdteske			elif [ $nulls -eq 2 ]; then
304247280Sdteske				# Only valid if begins/ends with `::'
305247280Sdteske				case "$ip" in
306247280Sdteske				::*|*::) : fall thru ;;
307247280Sdteske				*) return 2
308247280Sdteske				esac
309247280Sdteske			fi
310247280Sdteske			continue
311247280Sdteske		fi
312247280Sdteske
313247280Sdteske		#
314247280Sdteske		# Return error if not a valid hexadecimal short
315247280Sdteske		#
316247280Sdteske		case "$segment" in
317247280Sdteske		$h|$h$h|$h$h$h|$h$h$h$h)
318247280Sdteske			: valid segment of 1-4 hexadecimal digits
319247280Sdteske			;;
320247280Sdteske		*[!0-9A-Fa-f]*)
321247280Sdteske			# Segment contains at least one invalid char
322247280Sdteske
323247280Sdteske			# Return error immediately if not last segment
324247280Sdteske			[ $# -eq 0 ] || return 1
325247280Sdteske
326247280Sdteske			# Otherwise, check for legacy IPv4 notation
327247280Sdteske			case "$segment" in
328247280Sdteske			*[!0-9.]*)
329247280Sdteske				# Segment contains at least one invalid
330247280Sdteske				# character even for an IPv4 address
331247280Sdteske				return 1
332247280Sdteske			esac
333247280Sdteske
334247280Sdteske			# Return error if not enough segments
335247280Sdteske			if [ $nulls -eq 0 ]; then
336247280Sdteske				[ $nsegments -eq 7 ] || return 4
337247280Sdteske			fi
338247280Sdteske
339247280Sdteske			contains_ipv4_segment=1
340247280Sdteske
341247280Sdteske			# Validate the IPv4 address
342247280Sdteske			f_validate_ipaddr "$segment" ||
343247280Sdteske				return $(( 5 | $? << 4 ))
344247280Sdteske			;;
345247280Sdteske		*)
346247280Sdteske			# Segment characters are all valid but too many
347247280Sdteske			return 3
348247280Sdteske		esac
349247280Sdteske
350247280Sdteske	done
351247280Sdteske
352247280Sdteske	if [ $nulls -eq 1 ]; then
353247280Sdteske		# Single null segment cannot be at beginning/end
354247280Sdteske		case "$ip" in
355247280Sdteske		:*|*:) return 2
356247280Sdteske		esac
357247280Sdteske	fi
358247280Sdteske
359247280Sdteske	#
360247280Sdteske	# A legacy IPv4 address can span the last two 16-bit segments,
361247280Sdteske	# reducing the amount of maximum allowable segments by-one.
362247280Sdteske	#
363247280Sdteske	maxsegments=8
364247280Sdteske	if [ "$contains_ipv4_segment" ]; then
365247280Sdteske		maxsegments=7
366247280Sdteske	fi
367247280Sdteske
368247280Sdteske	case $nulls in
369247280Sdteske	# Return error if missing segments with no null spanner
370247280Sdteske	0) [ $nsegments -eq $maxsegments ] || return 4 ;;
371247280Sdteske	# Return error if null spanner with too many segments
372247280Sdteske	1) [ $nsegments -le $maxsegments ] || return 4 ;;
373247280Sdteske	# Return error if leading/trailing `::' with too many segments
374247280Sdteske	2) [ $nsegments -le $(( $maxsegments + 1 )) ] || return 4 ;;
375247280Sdteske	esac
376247280Sdteske
377247280Sdteske	return $SUCCESS
378247280Sdteske}
379247280Sdteske
380247280Sdteske# f_validate_netmask $netmask
381247280Sdteske#
382247280Sdteske# Returns zero if the given argument (a subnet mask) is of the proper format.
383247280Sdteske#
384247280Sdteske# The return status for invalid netmask is one of:
385247280Sdteske# 	1	One or more individual fields within the subnet mask (separated
386247280Sdteske# 	 	by dots) contains one or more invalid characters.
387247280Sdteske# 	2	One or more individual fields within the subnet mask are null
388247280Sdteske# 	 	and/or missing.
389247280Sdteske# 	3	One or more individual fields within the subnet mask exceeds
390247280Sdteske# 	 	the maximum of 255 (a full 8-bit register).
391247280Sdteske# 	4	The subnet mask has either too few or too many fields.
392247280Sdteske# 	5	One or more individual fields within the subnet mask is an
393247280Sdteske# 	 	invalid integer (only 0,128,192,224,240,248,252,254,255 are
394247280Sdteske# 	 	valid integers).
395247280Sdteske#
396247280Sdteskef_validate_netmask()
397247280Sdteske{
398247280Sdteske	local mask="$1"
399247280Sdteske
400247280Sdteske	# Track number of fields for error checking
401247280Sdteske	local nfields=0
402247280Sdteske
403247280Sdteske	local IFS="." # Split on `dot'
404247280Sdteske	for field in $mask; do
405247280Sdteske		# Return error if the field is null
406247280Sdteske		[ "$field" ] || return 2
407247280Sdteske
408247280Sdteske		# Return error if not a whole positive integer
409247280Sdteske		f_isinteger "$field" || return 1
410247280Sdteske
411247280Sdteske		# Return error if the field exceeds 255
412247280Sdteske		[ $field -gt 255 ] && return 3
413247280Sdteske
414247280Sdteske		# Return error if the field is an invalid integer
415247280Sdteske		case "$field" in
416252178Sdteske		0|128|192|224|240|248|252|254|255) : ;;
417252178Sdteske		*) return 5 ;;
418247280Sdteske		esac
419247280Sdteske
420247280Sdteske		nfields=$(( $nfields + 1 ))
421247280Sdteske	done
422247280Sdteske
423247280Sdteske	[ $nfields -eq 4 ] || return 4
424247280Sdteske}
425247280Sdteske
426247280Sdteske# f_validate_gateway $gateway $ipaddr $netmask
427247280Sdteske#
428247280Sdteske# Validate an IPv4 default gateway (aka router) address for a given IP address
429247280Sdteske# making sure the two are in the same network (able to ``talk'' to each other).
430247280Sdteske# Returns success if $ipaddr and $gateway are in the same network given subnet
431247280Sdteske# mask $netmask.
432247280Sdteske#
433247280Sdteskef_validate_gateway()
434247280Sdteske{
435247280Sdteske	local gateway="$1" ipaddr="$2" netmask="$3"
436247280Sdteske	local gwnum ipnum masknum
437247280Sdteske
438247280Sdteske	f_validate_ipaddr "$gateway" "$netmask" || return $FAILURE
439247280Sdteske
440247280Sdteske	f_inet_atoi "$netmask" masknum
441247280Sdteske	f_inet_atoi "$ipaddr"  ipnum
442247280Sdteske	f_inet_atoi "$gateway" gwnum
443247280Sdteske
444247280Sdteske	# Gateway must be within set of IPs reachable through interface
445247280Sdteske	[ $(( $ipnum & $masknum )) -eq \
446247280Sdteske	  $(( $gwnum & $masknum )) ] # Return status
447247280Sdteske}
448247280Sdteske
449247280Sdteske# f_dialog_validate_tcpip $hostname $gateway $nameserver $ipaddr $netmask
450247280Sdteske#
451247280Sdteske# Returns success if the arguments provided are valid for accessing a TCP/IP
452247280Sdteske# network, otherwise returns failure.
453247280Sdteske#
454247280Sdteskef_dialog_validate_tcpip()
455247280Sdteske{
456247280Sdteske	local hostname="$1" gateway="$2" nameserver="$3"
457247280Sdteske	local ipaddr="$4" netmask="$5"
458247280Sdteske	local ipnum masknum
459247280Sdteske
460247280Sdteske	if [ ! "$hostname" ]; then
461252795Sdteske		f_show_msg "$msg_must_specify_a_host_name_of_some_sort"
462247280Sdteske	elif ! f_validate_hostname "$hostname"; then
463252795Sdteske		f_show_msg "$msg_invalid_hostname_value"
464247280Sdteske	elif [ "$netmask" ] && ! f_validate_netmask "$netmask"; then
465252795Sdteske		f_show_msg "$msg_invalid_netmask_value"
466247280Sdteske	elif [ "$nameserver" ] &&
467252795Sdteske	     ! f_validate_ipaddr "$nameserver" &&
468252795Sdteske	     ! f_validate_ipaddr6 "$nameserver"; then
469252795Sdteske		f_show_msg "$msg_invalid_name_server_ip_address_specified"
470247280Sdteske	elif [ "$ipaddr" ] && ! f_validate_ipaddr "$ipaddr" "$netmask"; then
471252795Sdteske		f_show_msg "$msg_invalid_ipv4_address"
472247280Sdteske	elif [ "$gateway" -a "$gateway" != "NO" ] &&
473252795Sdteske	     ! f_validate_gateway "$gateway" "$ipaddr" "$netmask"; then
474252795Sdteske		f_show_msg "$msg_invalid_gateway_ipv4_address_specified"
475247280Sdteske	else
476256181Sdteske		return $DIALOG_OK
477247280Sdteske	fi
478247280Sdteske
479256181Sdteske	return $DIALOG_CANCEL
480247280Sdteske}
481247280Sdteske
482247280Sdteske# f_ifconfig_inet $interface [$var_to_set]
483247280Sdteske#
484247280Sdteske# Returns the IPv4 address associated with $interface. If $var_to_set is
485247280Sdteske# missing or NULL, the IP address is printed to standard output for capturing
486247280Sdteske# in a sub-shell (which is less-recommended because of performance degredation;
487247280Sdteske# for example, when called in a loop).
488247280Sdteske#
489247280Sdteske# This function is a two-parter. Below is the awk(1) portion of the function,
490247280Sdteske# afterward is the sh(1) function which utilizes the below awk script.
491247280Sdteske#
492247280Sdteskef_ifconfig_inet_awk='
493247280SdteskeBEGIN { found = 0 }
494247280Sdteske( $1 == "inet" ) \
495247280Sdteske{
496247280Sdteske	print $2
497247280Sdteske	found = 1
498247280Sdteske	exit
499247280Sdteske}
500247280SdteskeEND { exit ! found }
501247280Sdteske'
502247280Sdteskef_ifconfig_inet()
503247280Sdteske{
504247280Sdteske	local __interface="$1" __var_to_set="$2"
505247280Sdteske	if [ "$__var_to_set" ]; then
506247280Sdteske		local __ip
507247280Sdteske		__ip=$( ifconfig "$__interface" 2> /dev/null |
508247280Sdteske			awk "$f_ifconfig_inet_awk" )
509247280Sdteske		setvar "$__var_to_set" "$__ip"
510247280Sdteske	else
511247280Sdteske		ifconfig "$__interface" 2> /dev/null |
512247280Sdteske			awk "$f_ifconfig_inet_awk"
513247280Sdteske	fi
514247280Sdteske}
515247280Sdteske
516247280Sdteske# f_ifconfig_inet6 $interface [$var_to_set]
517247280Sdteske#
518247280Sdteske# Returns the IPv6 address associated with $interface. If $var_to_set is
519247280Sdteske# missing or NULL, the IP address is printed to standard output for capturing
520247280Sdteske# in a sub-shell (which is less-recommended because of performance degredation;
521247280Sdteske# for example, when called in a loop).
522247280Sdteske#
523247280Sdteske# This function is a two-parter. Below is the awk(1) portion of the function,
524247280Sdteske# afterward is the sh(1) function which utilizes the below awk script.
525247280Sdteske#
526247280Sdteskef_ifconfig_inet6_awk='
527247280SdteskeBEGIN { found = 0 }
528247280Sdteske( $1 == "inet6" ) \
529247280Sdteske{
530247280Sdteske	print $2
531247280Sdteske	found = 1
532247280Sdteske	exit
533247280Sdteske}
534247280SdteskeEND { exit ! found }
535247280Sdteske'
536247280Sdteskef_ifconfig_inet6()
537247280Sdteske{
538247280Sdteske	local __interface="$1" __var_to_set="$2"
539247280Sdteske	if [ "$__var_to_set" ]; then
540247280Sdteske		local __ip6
541247280Sdteske		__ip6=$( ifconfig "$__interface" 2> /dev/null |
542247280Sdteske			awk "$f_ifconfig_inet6_awk" )
543247280Sdteske		setvar "$__var_to_set" "$__ip6"
544247280Sdteske	else
545247280Sdteske		ifconfig "$__interface" 2> /dev/null |
546247280Sdteske			awk "$f_ifconfig_inet6_awk"
547247280Sdteske	fi
548247280Sdteske}
549247280Sdteske
550247280Sdteske# f_ifconfig_netmask $interface [$var_to_set]
551247280Sdteske#
552247280Sdteske# Returns the IPv4 subnet mask associated with $interface. If $var_to_set is
553247280Sdteske# missing or NULL, the netmask is printed to standard output for capturing in a
554247280Sdteske# sub-shell (which is less-recommended because of performance degredation; for
555247280Sdteske# example, when called in a loop).
556247280Sdteske#
557247280Sdteskef_ifconfig_netmask()
558247280Sdteske{
559247280Sdteske	local __interface="$1" __var_to_set="$2" __octets
560247280Sdteske	__octets=$( ifconfig "$__interface" 2> /dev/null | awk \
561247280Sdteske	'
562247280Sdteske		BEGIN { found = 0 }
563247280Sdteske		( $1 == "inet" ) \
564247280Sdteske		{
565247280Sdteske			printf "%s %s %s %s\n",
566247280Sdteske				substr($4,3,2),
567247280Sdteske				substr($4,5,2),
568247280Sdteske				substr($4,7,2),
569247280Sdteske				substr($4,9,2)
570247280Sdteske			found = 1
571247280Sdteske			exit
572247280Sdteske		}
573247280Sdteske		END { exit ! found }
574247280Sdteske	' ) || return $FAILURE
575247280Sdteske
576247280Sdteske	local __octet __netmask=
577247280Sdteske	for __octet in $__octets; do
578260678Sdteske		f_sprintf __netmask "%s.%u" "$__netmask" "0x$__octet"
579247280Sdteske	done
580247280Sdteske	__netmask="${__netmask#.}"
581247280Sdteske	if [ "$__var_to_set" ]; then
582247280Sdteske		setvar "$__var_to_set" "$__netmask"
583247280Sdteske	else
584247280Sdteske		echo $__netmask
585247280Sdteske	fi
586247280Sdteske}
587247280Sdteske
588247280Sdteske# f_route_get_default [$var_to_set]
589247280Sdteske#
590247280Sdteske# Returns the IP address of the currently active default router. If $var_to_set
591247280Sdteske# is missing or NULL, the IP address is printed to standard output for
592247280Sdteske# capturing in a sub-shell (which is less-recommended because of performance
593247280Sdteske# degredation; for example, when called in a loop).
594247280Sdteske#
595247280Sdteske# This function is a two-parter. Below is the awk(1) portion of the function,
596247280Sdteske# afterward is the sh(1) function which utilizes the below awk script.
597247280Sdteske#
598252086Sdteskef_route_get_default_awk='
599247280SdteskeBEGIN { found = 0 }
600247280Sdteske( $1 == "gateway:" ) \
601247280Sdteske{
602247280Sdteske	print $2
603247280Sdteske	found = 1
604247280Sdteske	exit
605247280Sdteske}
606247280SdteskeEND { exit ! found }
607247280Sdteske'
608247280Sdteskef_route_get_default()
609247280Sdteske{
610247280Sdteske	local __var_to_set="$1"
611247280Sdteske	if [ "$__var_to_set" ]; then
612247280Sdteske		local __ip
613247280Sdteske		__ip=$( route -n get default 2> /dev/null |
614247280Sdteske			awk "$f_route_get_default_awk" )
615247280Sdteske		setvar "$__var_to_set" "$__ip"
616247280Sdteske	else
617247280Sdteske		route -n get default 2> /dev/null |
618247280Sdteske			awk "$f_route_get_default_awk"
619247280Sdteske	fi
620247280Sdteske}
621247280Sdteske
622247280Sdteske# f_resolv_conf_nameservers [$var_to_set]
623247280Sdteske#
624247280Sdteske# Returns nameserver(s) configured in resolv.conf(5). If $var_to_set is missing
625247280Sdteske# or NULL, the list of nameservers is printed to standard output for capturing
626247280Sdteske# in a sub-shell (which is less-recommended because of performance degredation;
627247280Sdteske# for example, when called in a loop).
628247280Sdteske#
629247280Sdteske# This function is a two-parter. Below is the awk(1) portion of the function,
630247280Sdteske# afterward is the sh(1) function which utilizes the below awk script.
631247280Sdteske#
632247280Sdteskef_resolv_conf_nameservers_awk='
633247280SdteskeBEGIN { found = 0 }
634247280Sdteske( $1 == "nameserver" ) \
635247280Sdteske{
636247280Sdteske	print $2
637247280Sdteske	found = 1
638247280Sdteske}
639247280SdteskeEND { exit ! found }
640247280Sdteske'
641247280Sdteskef_resolv_conf_nameservers()
642247280Sdteske{
643247280Sdteske	local __var_to_set="$1"
644247280Sdteske	if [ "$__var_to_set" ]; then
645247280Sdteske		local __ns
646247280Sdteske		__ns=$( awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \
647247280Sdteske			2> /dev/null )
648247280Sdteske		setvar "$__var_to_set" "$__ns"
649247280Sdteske	else
650247280Sdteske		awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \
651247280Sdteske			2> /dev/null
652247280Sdteske	fi
653247280Sdteske}
654247280Sdteske
655247280Sdteske# f_config_resolv
656247280Sdteske#
657247280Sdteske# Attempts to configure resolv.conf(5) and ilk. Returns success if able to
658247280Sdteske# write the file(s), otherwise returns error status.
659247280Sdteske#
660247280Sdteske# Variables from variable.subr that are used in configuring resolv.conf(5) are
661247280Sdteske# as follows (all of which can be configured automatically through functions
662247280Sdteske# like f_dhcp_get_info() or manually):
663247280Sdteske#
664247280Sdteske# 	VAR_NAMESERVER
665247280Sdteske#		The nameserver to add in resolv.conf(5).
666247280Sdteske# 	VAR_DOMAINNAME
667247280Sdteske# 		The domain to configure in resolv.conf(5). Also used in the
668247280Sdteske# 		configuration of hosts(5).
669247280Sdteske# 	VAR_IPADDR
670247280Sdteske# 		The IPv4 address to configure in hosts(5).
671247280Sdteske# 	VAR_IPV6ADDR
672247280Sdteske# 		The IPv6 address to configure in hosts(5).
673247280Sdteske# 	VAR_HOSTNAME
674247280Sdteske# 		The hostname to associate with the IPv4 and/or IPv6 address in
675247280Sdteske# 		hosts(5).
676247280Sdteske#
677247280Sdteskef_config_resolv()
678247280Sdteske{
679247280Sdteske	local cp c6p dp hp
680247280Sdteske
681247280Sdteske	f_getvar $VAR_NAMESERVER cp
682247280Sdteske	if [ "$cp" ]; then
683247280Sdteske		case "$RESOLV_CONF" in
684247280Sdteske		*/*) f_quietly mkdir -p "${RESOLV_CONF%/*}" ;;
685247280Sdteske		esac
686247280Sdteske
687247280Sdteske		# Attempt to create/truncate the file
688247280Sdteske		( :> "$RESOLV_CONF" ) 2> /dev/null || return $FAILURE
689247280Sdteske
690247280Sdteske		f_getvar $VAR_DOMAINNAME dp &&
691247280Sdteske			printf "domain\t%s\n" "$dp" >> "$RESOLV_CONF"
692247280Sdteske		printf "nameserver\t%s\n" "$cp" >> "$RESOLV_CONF"
693247280Sdteske
694247280Sdteske		f_dprintf "Wrote out %s" "$RESOLV_CONF"
695247280Sdteske	fi
696247280Sdteske
697247280Sdteske	f_getvar $VAR_DOMAINNAME dp
698247280Sdteske	f_getvar $VAR_IPADDR cp
699247280Sdteske	f_getvar $VAR_IPV6ADDR c6p
700247280Sdteske	f_getvar $VAR_HOSTNAME hp
701247280Sdteske
702247280Sdteske	# Attempt to create the file if it doesn't already exist
703247280Sdteske	if [ ! -e "$ETC_HOSTS" ]; then
704247280Sdteske		case "$ETC_HOSTS" in
705247280Sdteske		*/*) f_quietly mkdir -p "${ETC_HOSTS%/*}" ;;
706247280Sdteske		esac
707247280Sdteske
708247280Sdteske		( :> "$ETC_HOSTS" ) 2> /dev/null || return $FAILURE
709247280Sdteske	fi
710247280Sdteske
711247280Sdteske	# Scan the file and add ourselves if not already configured
712247280Sdteske	awk -v dn="$dp" -v ip4="$cp" -v ip6="$c6p" -v hn="$hp" '
713247280Sdteske		BEGIN {
714247280Sdteske			local4found = local6found = 0
715247280Sdteske			hn4found = hn6found = h4found = h6found = 0
716247280Sdteske			h = ( match(hn, /\./) ? substr(hn, 0, RSTART-1) : "" )
717247280Sdteske		}
718247280Sdteske		($1 == "127.0.0.1") { local4found = 1 }
719247280Sdteske		($1 == "::1") { local6found = 1 }
720247280Sdteske		{
721247280Sdteske			for (n = 2; n <= NF; n++)
722247280Sdteske			{
723247280Sdteske				if ( $1 == ip4 ) {
724247280Sdteske					if ( $n == h ) h4found = 1
725247280Sdteske					if ( $n == hn ) hn4found = 1
726247280Sdteske					if ( $n == hn "." ) hn4found = 1
727247280Sdteske				}
728247280Sdteske				if ( $1 == ip6 ) {
729247280Sdteske					if ( $n == h ) h6found = 1
730247280Sdteske					if ( $n == hn ) hn6found = 1
731247280Sdteske					if ( $n == hn "." ) hn6found = 1
732247280Sdteske				}
733247280Sdteske			}
734247280Sdteske		}
735247280Sdteske		END {
736247280Sdteske			hosts = FILENAME
737247280Sdteske
738247280Sdteske			if ( ! local6found )
739247280Sdteske				printf "::1\t\t\tlocalhost%s\n",
740247280Sdteske				       ( dn ? " localhost." dn : "" ) >> hosts
741247280Sdteske			if ( ! local4found )
742247280Sdteske				printf "127.0.0.1\t\tlocalhost%s\n",
743247280Sdteske				       ( dn ? " localhost." dn : "" ) >> hosts
744247280Sdteske
745247280Sdteske			if ( ip6 && ! (h6found && hn6found))
746247280Sdteske			{
747247280Sdteske				printf "%s\t%s %s\n", ip6, hn, h >> hosts
748247280Sdteske				printf "%s\t%s.\n", ip6, hn >> hosts
749247280Sdteske			}
750247280Sdteske			else if ( ip6 )
751247280Sdteske			{
752247280Sdteske				if ( ! h6found )
753247280Sdteske					printf "%s\t%s.\n", ip6, h >> hosts
754247280Sdteske				if ( ! hn6found )
755247280Sdteske					printf "%s\t%s\n", ip6, hn >> hosts
756247280Sdteske			}
757247280Sdteske
758247280Sdteske			if ( ip4 && ! (h4found && hn4found))
759247280Sdteske			{
760247280Sdteske				printf "%s\t\t%s %s\n", ip4, hn, h >> hosts
761247280Sdteske				printf "%s\t\t%s.\n", ip4, hn >> hosts
762247280Sdteske			}
763247280Sdteske			else if ( ip4 )
764247280Sdteske			{
765247280Sdteske				if ( ! h4found )
766247280Sdteske					printf "%s\t\t%s.\n", ip4, h >> hosts
767247280Sdteske				if ( ! hn4found )
768247280Sdteske					printf "%s\t\t%s\n", ip4, hn >> hosts
769247280Sdteske			}
770247280Sdteske		}
771247280Sdteske	' "$ETC_HOSTS" 2> /dev/null || return $FAILURE
772247280Sdteske
773247280Sdteske	f_dprintf "Wrote out %s" "$ETC_HOSTS"
774247280Sdteske	return $SUCCESS
775247280Sdteske}
776247280Sdteske
777247280Sdteske# f_dhcp_parse_leases $leasefile struct_name
778247280Sdteske#
779247280Sdteske# Parse $leasefile and store the information for the most recent lease in a
780247280Sdteske# struct (see struct.subr for additional details) named `struct_name'. See
781247280Sdteske# DHCP_LEASE struct definition in the GLOBALS section above.
782247280Sdteske#
783247280Sdteskef_dhcp_parse_leases()
784247280Sdteske{
785247280Sdteske	local leasefile="$1" struct_name="$2"
786247280Sdteske
787247280Sdteske	[ "$struct_name" ] || return $FAILURE
788247280Sdteske
789247280Sdteske	if [ ! -e "$leasefile" ]; then
790247280Sdteske		f_dprintf "%s: No such file or directory" "$leasefile"
791247280Sdteske		return $FAILURE
792247280Sdteske	fi
793247280Sdteske
794247280Sdteske	f_struct "$struct_name" && f_struct_free "$struct_name"
795247280Sdteske	f_struct_new DHCP_LEASE "$struct_name"
796247280Sdteske
797247280Sdteske	eval "$( awk -v struct="$struct_name" '
798247280Sdteske		BEGIN {
799247280Sdteske			lease_found = 0
800247280Sdteske			keyword_list = " \
801247280Sdteske				interface	\
802247280Sdteske				fixed-address	\
803247280Sdteske				filename	\
804247280Sdteske				server-name	\
805247280Sdteske				script		\
806247280Sdteske				medium		\
807247280Sdteske			"
808247280Sdteske			split(keyword_list, keywords, FS)
809247280Sdteske
810247280Sdteske			time_list = "renew rebind expire"
811247280Sdteske			split(time_list, times, FS)
812247280Sdteske
813247280Sdteske			option_list = " \
814247280Sdteske				host-name		\
815247280Sdteske				subnet-mask		\
816247280Sdteske				routers			\
817247280Sdteske				domain-name-servers	\
818247280Sdteske				domain-name		\
819247280Sdteske				broadcast-address	\
820247280Sdteske				dhcp-lease-time		\
821247280Sdteske				dhcp-message-type	\
822247280Sdteske				dhcp-server-identifier	\
823247280Sdteske				dhcp-renewal-time	\
824247280Sdteske				dhcp-rebinding-time	\
825247280Sdteske			"
826247280Sdteske			split(option_list, options, FS)
827247280Sdteske		}
828247280Sdteske		function set_value(prop,value)
829247280Sdteske		{
830247280Sdteske			lease_found = 1
831247280Sdteske			gsub(/[^[:alnum:]_]/, "_", prop)
832247280Sdteske			sub(/;$/, "", value)
833247280Sdteske			sub(/^"/, "", value)
834247280Sdteske			sub(/"$/, "", value)
835247280Sdteske			sub(/,.*/, "", value)
836247280Sdteske			printf "%s set %s \"%s\"\n", struct, prop, value
837247280Sdteske		}
838247280Sdteske		/^lease {$/, /^}$/ \
839247280Sdteske		{
840247280Sdteske			if ( $0 ~ /^lease {$/ ) next
841247280Sdteske			if ( $0 ~ /^}$/ ) exit
842247280Sdteske
843247280Sdteske			for (k in keywords)
844247280Sdteske			{
845247280Sdteske				keyword = keywords[k]
846247280Sdteske				if ( $1 == keyword )
847247280Sdteske				{
848247280Sdteske					set_value(keyword, $2)
849247280Sdteske					next
850247280Sdteske				}
851247280Sdteske			}
852247280Sdteske
853247280Sdteske			for (t in times)
854247280Sdteske			{
855247280Sdteske				time = times[t]
856247280Sdteske				if ( $1 == time )
857247280Sdteske				{
858247280Sdteske					set_value(time, $2 " " $3 " " $4)
859247280Sdteske					next
860247280Sdteske				}
861247280Sdteske			}
862247280Sdteske
863247280Sdteske			if ( $1 != "option" ) next
864247280Sdteske			for (o in options)
865247280Sdteske			{
866247280Sdteske				option = options[o]
867247280Sdteske				if ( $2 == option )
868247280Sdteske				{
869247280Sdteske					set_value(option, $3)
870247280Sdteske					next
871247280Sdteske				}
872247280Sdteske			}
873247280Sdteske		}
874247280Sdteske		EXIT {
875247280Sdteske			if ( ! lease_found )
876247280Sdteske			{
877247280Sdteske				printf "f_struct_free \"%s\"\n", struct
878247280Sdteske				print "return $FAILURE"
879247280Sdteske			}
880247280Sdteske		}
881247280Sdteske	' "$leasefile" )"
882247280Sdteske}
883247280Sdteske
884247280Sdteske# f_dhcp_get_info $interface
885247280Sdteske#
886247280Sdteske# Parse the dhclient(8) lease database for $interface to obtain all the
887247280Sdteske# necessary IPv4 details necessary to communicate on the network. The retrieved
888247280Sdteske# information is stored in VAR_IPADDR, VAR_NETMASK, VAR_GATEWAY, and
889247280Sdteske# VAR_NAMESERVER.
890247280Sdteske#
891247280Sdteske# If reading the lease database fails, values are obtained from ifconfig(8) and
892247280Sdteske# route(8). If the DHCP lease did not provide a nameserver (or likewise, we
893247280Sdteske# were unable to parse the lease database), fall-back to resolv.conf(5) for
894247280Sdteske# obtaining the nameserver. Always returns success.
895247280Sdteske#
896247280Sdteskef_dhcp_get_info()
897247280Sdteske{
898247280Sdteske	local interface="$1" cp
899247280Sdteske	local leasefile="/var/db/dhclient.leases.$interface"
900247280Sdteske
901247280Sdteske	# If it fails, do it the old-fashioned way
902247280Sdteske	if f_dhcp_parse_leases "$leasefile" lease; then
903247280Sdteske		lease get fixed_address $VAR_IPADDR
904247280Sdteske		lease get subnet_mask $VAR_NETMASK
905247280Sdteske		lease get routers cp
906247280Sdteske		setvar $VAR_GATEWAY "${cp%%,*}"
907247280Sdteske		lease get domain_name_servers cp
908247280Sdteske		setvar $VAR_NAMESERVER "${cp%%,*}"
909247280Sdteske		lease get host_name cp &&
910247280Sdteske			setvar $VAR_HOSTNAME "$cp"
911247280Sdteske		f_struct_free lease
912247280Sdteske	else
913247280Sdteske		# Bah, now we have to get the information from ifconfig
914247280Sdteske		if f_debugging; then
915247280Sdteske			f_dprintf "DHCP configured interface returns %s" \
916247280Sdteske			          "$( ifconfig "$interface" )"
917247280Sdteske		fi
918247280Sdteske		f_ifconfig_inet "$interface" $VAR_IPADDR
919247280Sdteske		f_ifconfig_netmask "$interface" $VAR_NETMASK
920247280Sdteske		f_route_get_default $VAR_GATEWAY
921247280Sdteske	fi
922247280Sdteske
923247280Sdteske	# If we didn't get a name server value, hunt for it in resolv.conf
924247280Sdteske	local ns
925247280Sdteske	if [ -r "$RESOLV_CONF" ] && ! {
926247280Sdteske		f_getvar $VAR_NAMESERVER ns || [ "$ns" ]
927247280Sdteske	}; then
928247280Sdteske		f_resolv_conf_nameservers cp &&
929247280Sdteske			setvar $VAR_NAMESERVER ${cp%%[$IFS]*}
930247280Sdteske	fi
931247280Sdteske
932247280Sdteske	return $SUCCESS
933247280Sdteske}
934247280Sdteske
935247280Sdteske# f_rtsol_get_info $interface
936247280Sdteske#
937247280Sdteske# Returns the rtsol-provided IPv6 address associated with $interface. The
938247280Sdteske# retrieved IP address is stored in VAR_IPV6ADDR. Always returns success.
939247280Sdteske#
940247280Sdteskef_rtsol_get_info()
941247280Sdteske{
942247280Sdteske	local interface="$1" cp
943247280Sdteske	cp=$( ifconfig "$interface" 2> /dev/null | awk \
944247280Sdteske	'
945247280Sdteske		BEGIN { found = 0 }
946247280Sdteske		( $1 == "inet6" ) && ( $2 ~ /^fe80:/ ) \
947247280Sdteske		{
948247280Sdteske			print $2
949247280Sdteske			found = 1
950247280Sdteske			exit
951247280Sdteske		}
952247280Sdteske		END { exit ! found }
953247280Sdteske	' ) && setvar $VAR_IPV6ADDR "$cp"
954247280Sdteske}
955247280Sdteske
956247280Sdteske# f_host_lookup $host [$var_to_set]
957247280Sdteske#
958247280Sdteske# Use host(1) to lookup (or reverse) an Internet number from (or to) a name.
959247280Sdteske# Multiple answers are returned separated by a single space. If host(1) does
960247280Sdteske# not exit cleanly, its full output is provided and the return status is 1.
961247280Sdteske#
962247280Sdteske# If nsswitch.conf(5) has been configured to query local access first for the
963247280Sdteske# `hosts' database, we'll manually check hosts(5) first (preventing host(1)
964247280Sdteske# from hanging in the event that DNS goes awry).
965247280Sdteske#
966247280Sdteske# If $var_to_set is missing or NULL, the list of IP addresses is printed to
967247280Sdteske# standard output for capturing in a sub-shell (which is less-recommended
968247280Sdteske# because of performance degredation; for example, when called in a loop).
969247280Sdteske#
970247280Sdteske# The variables from variable.subr used in looking up the host are as follows
971247280Sdteske# (which are set manually):
972247280Sdteske#
973247280Sdteske# 	VAR_IPV6_ENABLE [Optional]
974247280Sdteske# 		If set to "YES", enables the lookup of IPv6 addresses and IPv4
975247280Sdteske# 		address. IPv6 addresses, if any, will come before IPv4. Note
976247280Sdteske# 		that if nsswitch.conf(5) shows an affinity for "files" for the
977247280Sdteske# 		"host" database and there is a valid entry in hosts(5) for
978247280Sdteske# 		$host, this setting currently has no effect (an IPv4 address
979247280Sdteske# 		can supersede an IPv6 address). By design, hosts(5) overrides
980247280Sdteske# 		any preferential treatment. Otherwise, if this variable is not
981247280Sdteske# 		set, IPv6 addresses will not be used (IPv4 addresses will
982247280Sdteske# 		specifically be requested from DNS).
983247280Sdteske#
984247280Sdteske# This function is a two-parter. Below is the awk(1) portion of the function,
985247280Sdteske# afterward is the sh(1) function which utilizes the below awk script.
986247280Sdteske#
987247280Sdteskef_host_lookup_awk='
988247280SdteskeBEGIN{ addrs = "" }
989247280Sdteske!/^[[:space:]]*(#|$)/ \
990247280Sdteske{
991247280Sdteske	for (n=1; n++ < NF;) if ($n == name)
992247280Sdteske		addrs = addrs (addrs ? " " : "") $1
993247280Sdteske}
994247280SdteskeEND {
995247280Sdteske	if (addrs) print addrs
996247280Sdteske	exit !addrs
997247280Sdteske}
998247280Sdteske'
999247280Sdteskef_host_lookup()
1000247280Sdteske{
1001247280Sdteske	local __host="$1" __var_to_set="$2"
1002247280Sdteske	f_dprintf "f_host_lookup: host=[%s]" "$__host"
1003247280Sdteske
1004247280Sdteske	# If we're configured to look at local files first, do that
1005247280Sdteske	if awk '/^hosts:/{exit !($2=="files")}' "$NSSWITCH_CONF"; then
1006247280Sdteske		if [ "$__var_to_set" ]; then
1007247280Sdteske			local __cp
1008247280Sdteske			if __cp=$( awk -v name="$__host" \
1009247280Sdteske				"$f_host_lookup_awk" "$ETC_HOSTS" )
1010247280Sdteske			then
1011247280Sdteske				setvar "$__var_to_set" "$__cp"
1012247280Sdteske				return $SUCCESS
1013247280Sdteske			fi
1014247280Sdteske		else
1015247280Sdteske			awk -v name="$__host" \
1016247280Sdteske				"$f_host_lookup_awk" "$ETC_HOSTS" &&
1017247280Sdteske				return $SUCCESS
1018247280Sdteske		fi
1019247280Sdteske	fi
1020247280Sdteske
1021247280Sdteske	#
1022247280Sdteske	# Fall back to host(1) -- which is further governed by nsswitch.conf(5)
1023247280Sdteske	#
1024247280Sdteske
1025258420Sdteske	local __output __ip6 __addrs=
1026247280Sdteske	f_getvar $VAR_IPV6_ENABLE __ip6
1027258420Sdteske
1028258420Sdteske	# If we have a TCP media type configured, check for an SRV record
1029258420Sdteske	local __srvtypes=
1030258420Sdteske	{ f_quietly f_getvar $VAR_HTTP_PATH ||
1031258420Sdteske	  f_quietly f_getvar $VAR_HTTP_PROXY_PATH
1032258420Sdteske	} && __srvtypes="$__srvtypes _http._tcp"
1033258420Sdteske	f_quietly f_getvar $VAR_FTP_PATH && __srvtypes="$__srvtypes _ftp._tcp"
1034258420Sdteske	f_quietly f_getvar $VAR_NFS_PATH &&
1035258420Sdteske		__srvtypes="$__srvtypes _nfs._tcp _nfs._udp"
1036258420Sdteske
1037258420Sdteske	# Calculate wait time as dividend of total time and host(1) invocations
1038258420Sdteske	local __host_runs __wait
1039260678Sdteske	f_count __host_runs $__srvtypes
1040247280Sdteske	if [ "$__ip6" = "YES" ]; then
1041260678Sdteske		__host_runs=$(( $__host_runs + 2 ))
1042258420Sdteske	else
1043260678Sdteske		__host_runs=$(( $__host_runs + 1 ))
1044258420Sdteske	fi
1045258420Sdteske	f_getvar $VAR_MEDIA_TIMEOUT __wait
1046258420Sdteske	[ "$__wait" ] && __wait="-W $(( $__wait / $__host_runs ))"
1047258420Sdteske
1048258420Sdteske	# Query SRV types first (1st host response taken as new host to query)
1049258420Sdteske	for __type in $__srvtypes; do
1050258420Sdteske		if __output=$(
1051258420Sdteske			host -t SRV $__wait -- "$__type.$__host" \
1052258420Sdteske			2> /dev/null
1053258420Sdteske		); then
1054258420Sdteske			__host=$( echo "$__output" |
1055258420Sdteske					awk '/ SRV /{print $NF;exit}' )
1056258420Sdteske			break
1057258420Sdteske		fi
1058258420Sdteske	done
1059258420Sdteske
1060258420Sdteske	# Try IPv6 first (if enabled)
1061258420Sdteske	if [ "$__ip6" = "YES" ]; then
1062247280Sdteske		if ! __output=$( host -t AAAA $__wait -- "$__host" 2>&1 ); then
1063247280Sdteske			# An error occurred, display in-full and return error
1064247280Sdteske			[ "$__var_to_set" ] &&
1065247280Sdteske				setvar "$__var_to_set" "$__output"
1066247280Sdteske			return $FAILURE
1067247280Sdteske		fi
1068258420Sdteske		# Add the IPv6 addresses and fall-through to collect IPv4 too
1069247280Sdteske		__addrs=$( echo "$__output" | awk '/ address /{print $NF}' )
1070247280Sdteske	fi
1071258420Sdteske
1072258420Sdteske	# Good ol' IPv4
1073247280Sdteske	if ! __output=$( host -t A $__wait -- "$__host" 2>&1 ); then
1074247280Sdteske		# An error occurred, display it in-full and return error
1075247280Sdteske		[ "$__var_to_set" ] && setvar "$__var_to_set" "$__output"
1076247280Sdteske		return $FAILURE
1077247280Sdteske	fi
1078258420Sdteske
1079247280Sdteske	__addrs="$__addrs${__addrs:+ }$(
1080247280Sdteske		echo "$__output" | awk '/ address /{print $NF}' )"
1081247280Sdteske	if [ "$__var_to_set" ]; then
1082247280Sdteske		setvar "$__var_to_set" "$__addrs"
1083247280Sdteske	else
1084247280Sdteske		echo $__addrs
1085247280Sdteske	fi
1086247280Sdteske}
1087247280Sdteske
1088247280Sdteske# f_device_dialog_tcp $device
1089247280Sdteske#
1090247280Sdteske# This is it - how to get TCP setup values. Prompt the user to edit/confirm the
1091247280Sdteske# interface, gateway, nameserver, and hostname settings -- all required for
1092247280Sdteske# general TCP/IP access.
1093247280Sdteske#
1094247280Sdteske# Variables from variable.subr that can be used to sript user input:
1095247280Sdteske#
1096247280Sdteske# 	VAR_NO_INET6
1097247280Sdteske# 		If set, prevents asking the user if they would like to use
1098247280Sdteske# 		rtsol(8) to check for an IPv6 router.
1099247280Sdteske# 	VAR_TRY_RTSOL
1100247280Sdteske# 		If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the
1101247280Sdteske# 		user if they would like to try the IPv6 RouTer SOLicitation
1102247280Sdteske# 		utility (rtsol(8)) to get IPv6 information. Ignored if
1103247280Sdteske# 		VAR_NO_INET6 is set.
1104247280Sdteske# 	VAR_TRY_DHCP
1105247280Sdteske# 		If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the
1106247280Sdteske# 		user if they would like to try to acquire IPv4 connection
1107247280Sdteske# 		settings from a DHCP server using dhclient(8).
1108247280Sdteske#
1109247280Sdteske# 	VAR_GATEWAY	Default gateway to use.
1110247280Sdteske# 	VAR_IPADDR	Interface address to assign.
1111247280Sdteske# 	VAR_NETMASK	Interface subnet mask.
1112247280Sdteske# 	VAR_EXTRAS	Extra interface options to ifconfig(8).
1113247280Sdteske# 	VAR_HOSTNAME	Hostname to set.
1114247280Sdteske# 	VAR_DOMAINNAME	Domain name to use.
1115247280Sdteske# 	VAR_NAMESERVER	DNS nameserver to use when making lookups.
1116247280Sdteske# 	VAR_IPV6ADDR	IPv6 interface address.
1117247280Sdteske#
1118247280Sdteske# In addition, the following variables are used in acquiring network settings
1119247280Sdteske# from the user:
1120247280Sdteske#
1121247280Sdteske# 	VAR_NONINTERACTIVE
1122247280Sdteske# 		If set (such as when running in a script), prevents asking the
1123247280Sdteske# 		user questions or displaying the usual prompts, etc.
1124247280Sdteske# 	VAR_NETINTERACTIVE
1125247280Sdteske# 		The one exception to VAR_NONINTERACTIVE is VAR_NETINTERACTIVE,
1126247280Sdteske# 		which if set will prompt the user to try RTSOL (unless
1127247280Sdteske# 		VAR_TRY_RTSOL has been set), try DHCP (unless VAR_TRY_DHCP has
1128247280Sdteske# 		been set), and display the network verification dialog. This
1129247280Sdteske# 		allows you to have a mostly non-interactive script that still
1130247280Sdteske# 		prompts for network setup/confirmation.
1131247280Sdteske#
1132247280Sdteske# After successfull execution, the following variables are set:
1133247280Sdteske#
1134247280Sdteske# 	VAR_IFCONFIG + $device (e.g., `ifconfig_em0')
1135247280Sdteske#               Defines the ifconfig(8) properties specific to $device.
1136247280Sdteske#
1137247280Sdteskef_device_dialog_tcp()
1138247280Sdteske{
1139266290Sdteske	local dev="$1" devname cp n
1140247280Sdteske	local use_dhcp="" use_rtsol=""
1141247280Sdteske	local _ipaddr _netmask _extras
1142247280Sdteske
1143256181Sdteske	[ "$dev" ] || return $DIALOG_CANCEL
1144266290Sdteske	f_struct "$dev" get name devname || return $DIALOG_CANCEL
1145247280Sdteske
1146247280Sdteske	# Initialize vars from previous device values
1147247280Sdteske	local private
1148266290Sdteske	$dev get private private
1149247280Sdteske	if [ "$private" ] && f_struct "$private"; then
1150247280Sdteske		$private get ipaddr    _ipaddr
1151247280Sdteske		$private get netmask   _netmask
1152247280Sdteske		$private get extras    _extras
1153247280Sdteske		$private get use_dhcp  use_dhcp
1154247280Sdteske		$private get use_rtsol use_rtsol
1155247280Sdteske	else # See if there are any defaults
1156247280Sdteske
1157247280Sdteske		#
1158247280Sdteske		# This is a hack so that the dialogs below are interactive in a
1159247280Sdteske		# script if we have requested interactive behavior.
1160247280Sdteske		#
1161247280Sdteske		local old_interactive=
1162247280Sdteske		if ! f_interactive && f_netinteractive; then
1163247280Sdteske			f_getvar $VAR_NONINTERACTIVE old_interactive
1164247280Sdteske			unset $VAR_NONINTERACTIVE
1165247280Sdteske		fi
1166247280Sdteske
1167247280Sdteske		#
1168247280Sdteske		# Try a RTSOL scan if such behavior is desired.
1169247280Sdteske		# If the variable was configured and is YES, do it.
1170247280Sdteske		# If it was configured to anything else, treat it as NO.
1171247280Sdteske		# Otherwise, ask the question interactively.
1172247280Sdteske		#
1173247280Sdteske		local try6
1174251268Sdteske		if ! f_isset $VAR_NO_INET6 && {
1175247280Sdteske		   { f_getvar $VAR_TRY_RTSOL try6 && [ "$try6" = "YES" ]; } ||
1176247280Sdteske		   {
1177251268Sdteske			# Only prompt the user when VAR_TRY_RTSOL is unset
1178251268Sdteske			! f_isset $VAR_TRY_RTSOL &&
1179251268Sdteske				f_dialog_noyes "$msg_try_ipv6_configuration"
1180247280Sdteske		   }
1181247280Sdteske		}; then
1182247280Sdteske			local i
1183247280Sdteske
1184247280Sdteske			f_quietly sysctl net.inet6.ip6.forwarding=0
1185247280Sdteske			f_quietly sysctl net.inet6.ip6.accept_rtadv=1
1186266290Sdteske			f_quietly ifconfig $devname up
1187247280Sdteske
1188247280Sdteske			i=$( sysctl -n net.inet6.ip6.dad_count )
1189247280Sdteske			sleep $(( $i + 1 ))
1190247280Sdteske
1191247280Sdteske			f_quietly mkdir -p /var/run
1192247280Sdteske			f_dialog_info "$msg_scanning_for_ra_servers"
1193266290Sdteske			if f_quietly rtsol $devname; then
1194247280Sdteske				i=$( sysctl -n net.inet6.ip6.dad_count )
1195247280Sdteske				sleep $(( $i + 1 ))
1196266290Sdteske				f_rtsol_get_info $devname
1197247280Sdteske				use_rtsol=1
1198247280Sdteske			else
1199247280Sdteske				use_rtsol=
1200247280Sdteske			fi
1201247280Sdteske		fi
1202247280Sdteske
1203247280Sdteske		#
1204247280Sdteske		# Try a DHCP scan if such behavior is desired.
1205247280Sdteske		# If the variable was configured and is YES, do it.
1206247280Sdteske		# If it was configured to anything else, treat it as NO.
1207247280Sdteske		# Otherwise, ask the question interactively.
1208247280Sdteske		#
1209247280Sdteske		local try4
1210247280Sdteske		if { f_getvar $VAR_TRY_DHCP try4 && [ "$try4" = "YES" ]; } || {
1211251268Sdteske			# Only prompt the user when VAR_TRY_DHCP is unset
1212251268Sdteske			! f_isset $VAR_TRY_DHCP &&
1213251268Sdteske				f_dialog_noyes "$msg_try_dhcp_configuration"
1214247280Sdteske		}; then
1215266290Sdteske			f_quietly ifconfig $devname delete
1216247280Sdteske			f_quietly mkdir -p /var/db
1217247280Sdteske			f_quietly mkdir -p /var/run
1218247280Sdteske			f_quietly mkdir -p /tmp
1219247280Sdteske
1220247280Sdteske			local msg="$msg_scanning_for_dhcp_servers"
1221247280Sdteske			trap - SIGINT
1222247280Sdteske			( # Execute in sub-shell to allow/catch Ctrl-C
1223247280Sdteske			  trap 'exit $FAILURE' SIGINT
1224247280Sdteske			  if [ "$USE_XDIALOG" ]; then
1225266290Sdteske			  	f_quietly dhclient $devname |
1226247280Sdteske			  			f_xdialog_info "$msg"
1227247280Sdteske			  else
1228247280Sdteske			  	f_dialog_info "$msg"
1229266290Sdteske			  	f_quietly dhclient $devname
1230247280Sdteske			  fi
1231247280Sdteske			)
1232247280Sdteske			local retval=$?
1233247280Sdteske			trap 'f_interrupt' SIGINT
1234247280Sdteske			if [ $retval -eq $SUCCESS ]; then
1235266290Sdteske				f_dhcp_get_info $devname
1236247280Sdteske				use_dhcp=1
1237247280Sdteske			else
1238247280Sdteske				use_dhcp=
1239247280Sdteske			fi
1240247280Sdteske		fi
1241247280Sdteske
1242247280Sdteske		# Restore old VAR_NONINTERACTIVE if needed.
1243247280Sdteske		[ "$old_interactive" ] &&
1244247280Sdteske			setvar $VAR_NONINTERACTIVE "$old_interactive"
1245247280Sdteske
1246247280Sdteske		# Special hack so it doesn't show up oddly in the menu
1247247280Sdteske		local gw
1248247280Sdteske		if f_getvar $VAR_GATEWAY gw && [ "$gw" = "NO" ]; then
1249247280Sdteske			setvar $VAR_GATEWAY ""
1250247280Sdteske		fi
1251247280Sdteske
1252247280Sdteske		# Get old IP address from variable space, if available
1253247280Sdteske		if [ ! "$_ipaddr" ]; then
1254247280Sdteske			if f_getvar $VAR_IPADDR cp; then
1255247280Sdteske				_ipaddr="$cp"
1256266290Sdteske			elif f_getvar ${devname}_$VAR_IPADDR cp; then
1257247280Sdteske				_ipaddr="$cp"
1258247280Sdteske			fi
1259247280Sdteske		fi
1260247280Sdteske
1261247280Sdteske		# Get old netmask from variable space, if available
1262247280Sdteske		if [ ! "$_netmask" ]; then
1263247280Sdteske			if f_getvar $VAR_NETMASK cp; then
1264247280Sdteske				_netmask="$cp"
1265266290Sdteske			elif f_getvar ${devname}_$VAR_NETMASK cp; then
1266247280Sdteske				_netmask="$cp"
1267247280Sdteske			fi
1268247280Sdteske		fi
1269247280Sdteske
1270247280Sdteske		# Get old extras string from variable space, if available
1271247280Sdteske		if [ ! "$_extras" ]; then
1272247280Sdteske			if f_getvar $VAR_EXTRAS cp; then
1273247280Sdteske				_extras="$cp"
1274266290Sdteske			elif f_getvar ${devname}_$VAR_EXTRAS cp; then
1275247280Sdteske				_extras="$cp"
1276247280Sdteske			fi
1277247280Sdteske		fi
1278247280Sdteske	fi
1279247280Sdteske
1280247280Sdteske	# Look up values already recorded with the system, or blank the string
1281247280Sdteske	# variables ready to accept some new data
1282247280Sdteske	local _hostname _gateway _nameserver
1283247280Sdteske	f_getvar $VAR_HOSTNAME _hostname
1284247280Sdteske	case "$_hostname" in
1285247280Sdteske	*.*) : do nothing ;; # Already fully-qualified
1286247280Sdteske	*)
1287247280Sdteske		f_getvar $VAR_DOMAINNAME cp
1288247280Sdteske		[ "$cp" ] && _hostname="$_hostname.$cp"
1289247280Sdteske	esac
1290247280Sdteske	f_getvar $VAR_GATEWAY _gateway
1291247280Sdteske	f_getvar $VAR_NAMESERVER _nameserver
1292247280Sdteske
1293247280Sdteske	# Re-check variables for initial inheritance before heading into dialog
1294247280Sdteske	[ "$_hostname" ] || _hostname="${HOSTNAME:-$( hostname )}"
1295247280Sdteske	[ "$_gateway" ] || f_route_get_default _gateway
1296247280Sdteske	[ ! "$_nameserver" ] &&
1297247280Sdteske		f_resolv_conf_nameservers cp && _nameserver=${cp%%[$IFS]*}
1298266290Sdteske	[ "$_ipaddr" ] || f_ifconfig_inet $devname _ipaddr
1299266290Sdteske	[ "$_netmask" ] || f_ifconfig_netmask $devname _netmask
1300247280Sdteske
1301247280Sdteske	# If non-interactive, jump over dialog section and into config section
1302247280Sdteske	if f_netinteractive || f_interactive || [ ! "$_hostname" ]
1303247280Sdteske	then
1304247280Sdteske		[ ! "$_hostname" ] && f_interactive &&
1305252795Sdteske			f_show_msg "$msg_hostname_variable_not_set"
1306247280Sdteske
1307247280Sdteske		local title=" $msg_network_configuration "
1308247280Sdteske		local hline="$hline_alnum_arrows_punc_tab_enter"
1309247280Sdteske		local extras_help="$tcplayout_extras_help"
1310247280Sdteske
1311247280Sdteske		# Modify the help line for PLIP config
1312266290Sdteske		[ "${devname#plip}" != "$devname" ] &&
1313247280Sdteske			extras_help="$tcplayout_extras_help_for_plip"
1314247280Sdteske
1315247280Sdteske		f_getvar $VAR_IPV6ADDR cp && [ "$cp" ] &&
1316247280Sdteske			title="$title($msg_ipv6_ready) "
1317247280Sdteske
1318247280Sdteske		if [ ! "$USE_XDIALOG" ]; then
1319247280Sdteske			local prompt="$msg_dialog_mixedform_navigation_help"
1320247280Sdteske			# Calculate center position for displaying device label
1321266290Sdteske			local devlabel="$msg_configuration_for_interface"
1322266290Sdteske			devlabel="$devlabel $devname"
1323247280Sdteske			local width=54
1324247280Sdteske			local n=$(( $width/2 - (${#devlabel} + 4)/2 - 2 ))
1325247280Sdteske
1326247280Sdteske			while :; do
1327247280Sdteske				cp=$( $DIALOG \
1328247280Sdteske					--title "$title"                     \
1329247280Sdteske					--backtitle "$DIALOG_BACKTITLE"      \
1330247280Sdteske					--hline "$hline"                     \
1331247280Sdteske					--item-help                          \
1332247280Sdteske					--ok-label "$msg_ok"                 \
1333247280Sdteske					--cancel-label "$msg_cancel"         \
1334247280Sdteske					--help-button                        \
1335247280Sdteske					--help-label "$msg_help"             \
1336247280Sdteske					--mixedform "$prompt" 16 $width 9    \
1337247280Sdteske					"$msg_host_name_including_domain:" 1 2 \
1338247280Sdteske						"$_hostname" 2 3 45 255 0    \
1339247280Sdteske						"$tcplayout_hostname_help"   \
1340247280Sdteske					"$msg_ipv4_gateway:" 3 2             \
1341247280Sdteske						"$_gateway" 4 3 16 15 0      \
1342247280Sdteske						"$tcplayout_gateway_help"    \
1343247280Sdteske					"$msg_name_server:" 3 31             \
1344247280Sdteske						"$_nameserver" 4 32 16 15 0  \
1345247280Sdteske						"$tcplayout_nameserver_help" \
1346247280Sdteske					"- $devlabel -" 5 $n "" 0 0 0 0 3 "" \
1347247280Sdteske					"$msg_ipv4_address:" 6 6             \
1348247280Sdteske						"$_ipaddr" 7 7 16 15 0       \
1349247280Sdteske						"$tcplayout_ipaddr_help"     \
1350247280Sdteske					"$msg_netmask:" 6 31                 \
1351247280Sdteske						"$_netmask" 7 32 16 15 0     \
1352247280Sdteske						"$tcplayout_netmask_help"    \
1353247280Sdteske					"$msg_extra_options_to_ifconfig" 8 6 \
1354247280Sdteske						"$_extras" 9 7 41 2048 0     \
1355247280Sdteske						"$extras_help"               \
1356247280Sdteske					2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
1357247280Sdteske
1358247280Sdteske				# --mixed-form always returns 0, we have to
1359247280Sdteske				# use the returned data to determine button
1360247280Sdteske				if [ ! "$cp" ]; then
1361247280Sdteske					# User either chose "Cancel", pressed
1362247280Sdteske					# ESC, or blanked every form field
1363256181Sdteske					return $DIALOG_CANCEL
1364247280Sdteske				else
1365247280Sdteske					n=$( echo "$cp" | f_number_of_lines )
1366247280Sdteske					[ $n -eq 1 ] && case "$cp" in HELP*)
1367247280Sdteske						# User chose "Help"
1368247280Sdteske						f_show_help "$TCP_HELPFILE"
1369247280Sdteske						continue
1370247280Sdteske					esac
1371247280Sdteske				fi
1372247280Sdteske
1373247280Sdteske				# Turn mixed-form results into env variables
1374247280Sdteske				eval "$( echo "$cp" | awk '
1375247280Sdteske				BEGIN {
1376247280Sdteske					n = 0
1377247280Sdteske					field[++n] = "_hostname"
1378247280Sdteske					field[++n] = "_gateway"
1379247280Sdteske					field[++n] = "_nameserver"
1380247280Sdteske					field[++n] = "_ipaddr"
1381247280Sdteske					field[++n] = "_netmask"
1382247280Sdteske					field[++n] = "_extras"
1383247280Sdteske					nfields = n
1384247280Sdteske					n = 0
1385247280Sdteske				}
1386247280Sdteske				{
1387247280Sdteske					gsub(/'\''/, "'\'\\\\\'\''")
1388247280Sdteske					sub(/[[:space:]]*$/, "")
1389247280Sdteske					value[field[++n]] = $0
1390247280Sdteske				}
1391247280Sdteske				END {
1392247280Sdteske					for ( n = 1; n <= nfields; n++ )
1393247280Sdteske					{
1394247280Sdteske						printf "%s='\''%s'\'';\n",
1395247280Sdteske						       field[n],
1396247280Sdteske						       value[field[n]]
1397247280Sdteske					}
1398247280Sdteske				}' )"
1399247280Sdteske
1400247280Sdteske				f_dialog_validate_tcpip \
1401247280Sdteske					"$_hostname" \
1402247280Sdteske					"$_gateway" \
1403247280Sdteske					"$_nameserver" \
1404247280Sdteske					"$_ipaddr" \
1405247280Sdteske					"$_netmask" \
1406247280Sdteske					&& break
1407247280Sdteske			done
1408247280Sdteske		else
1409247280Sdteske			# Xdialog(1) does not support --mixed-form
1410247280Sdteske			# Create a persistent menu instead
1411247280Sdteske
1412247280Sdteske			f_dialog_title "$msg_network_configuration"
1413251269Sdteske			local prompt=
1414247280Sdteske
1415247280Sdteske			while :; do
1416247280Sdteske				cp=$( $DIALOG \
1417247280Sdteske					--title "$DIALOG_TITLE"               \
1418247280Sdteske					--backtitle "$DIALOG_BACKTITLE"       \
1419247280Sdteske					--hline "$hline"                      \
1420247280Sdteske					--item-help                           \
1421247280Sdteske					--ok-label "$msg_ok"                  \
1422247280Sdteske					--cancel-label "$msg_cancel"          \
1423247280Sdteske					--help ""                             \
1424247280Sdteske					--menu "$prompt" 21 60 8              \
1425247280Sdteske					"$msg_accept_continue" ""             \
1426247280Sdteske						"$tcplayout_accept_cont_help" \
1427247280Sdteske					"$msg_host_name_including_domain:"    \
1428247280Sdteske						"$_hostname"                  \
1429247280Sdteske						"$tcplayout_hostname_help"    \
1430247280Sdteske					"$msg_ipv4_gateway:" "$_gateway"      \
1431247280Sdteske						"$tcplayout_gateway_help"     \
1432247280Sdteske					"$msg_name_server:" "$_nameserver"    \
1433247280Sdteske						"$tcplayout_nameserver_help"  \
1434247280Sdteske					"$msg_ipv4_address:" "$_ipaddr"       \
1435247280Sdteske						"$tcplayout_ipaddr_help"      \
1436247280Sdteske					"$msg_netmask:" "$_netmask"           \
1437247280Sdteske						"$tcplayout_netmask_help"     \
1438247280Sdteske					"$msg_extra_options_to_ifconfig"      \
1439247280Sdteske						"$_extras" "$extras_help"     \
1440247280Sdteske					2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1441247280Sdteske				)
1442247280Sdteske				local retval=$?
1443251236Sdteske				f_dialog_data_sanitize cp
1444247280Sdteske				f_dprintf "retval=%u mtag=[%s]" $retval "$cp"
1445247280Sdteske
1446256181Sdteske				if [ $retval -eq $DIALOG_HELP ]; then
1447247280Sdteske					f_show_help "$TCP_HELPFILE"
1448247280Sdteske					continue
1449256181Sdteske				elif [ $retval -ne $DIALOG_OK ]; then
1450247280Sdteske					f_dialog_title_restore
1451256181Sdteske					return $DIALOG_CANCEL
1452247280Sdteske				fi
1453247280Sdteske
1454247280Sdteske				case "$cp" in
1455247280Sdteske				"$msg_accept_continue")
1456247280Sdteske					f_dialog_validate_tcpip \
1457247280Sdteske						"$_hostname" \
1458247280Sdteske						"$_gateway" \
1459247280Sdteske						"$_nameserver" \
1460247280Sdteske						"$_ipaddr" \
1461247280Sdteske						"$_netmask" \
1462247280Sdteske						&& break ;;
1463247280Sdteske				"$msg_host_name_including_domain:")
1464251242Sdteske					f_dialog_input cp "$cp" "$_hostname" \
1465251242Sdteske						&& _hostname="$cp" ;;
1466247280Sdteske				"$msg_ipv4_gateway:")
1467251242Sdteske					f_dialog_input cp "$cp" "$_gateway" \
1468251242Sdteske						&& _gateway="$cp" ;;
1469247280Sdteske				"$msg_name_server:")
1470251242Sdteske					f_dialog_input cp "$cp" "$_nameserver" \
1471251242Sdteske						&& _nameserver="$cp" ;;
1472247280Sdteske				"$msg_ipv4_address:")
1473251242Sdteske					f_dialog_input cp "$cp" "$_ipaddr" \
1474251242Sdteske						&& _ipaddr="$cp" ;;
1475247280Sdteske				"$msg_netmask:")
1476251242Sdteske					f_dialog_input cp "$cp" "$_netmask" \
1477251242Sdteske						&& _netmask="$cp" ;;
1478247280Sdteske				"$msg_extra_options_to_ifconfig")
1479251242Sdteske					f_dialog_input cp "$cp" "$_extras" \
1480251242Sdteske						&& _extras="$cp" ;;
1481247280Sdteske				esac
1482247280Sdteske			done
1483247280Sdteske
1484247280Sdteske			f_dialog_title_restore
1485247280Sdteske
1486247280Sdteske		fi # XDIALOG
1487247280Sdteske
1488247280Sdteske	fi # interactive
1489247280Sdteske
1490247280Sdteske	# We actually need to inform the rest of bsdconfig about this
1491247280Sdteske	# data now if the user hasn't selected cancel.
1492247280Sdteske
1493247280Sdteske	if [ "$_hostname" ]; then
1494247280Sdteske		setvar $VAR_HOSTNAME "$_hostname"
1495247280Sdteske		f_quietly hostname "$_hostname"
1496247280Sdteske		case "$_hostname" in
1497247280Sdteske		*.*) setvar $VAR_DOMAINNAME "${_hostname#*.}" ;;
1498247280Sdteske		esac
1499247280Sdteske	fi
1500247280Sdteske	[ "$_gateway"    ] && setvar $VAR_GATEWAY    "$_gateway"
1501247280Sdteske	[ "$_nameserver" ] && setvar $VAR_NAMESERVER "$_nameserver"
1502247280Sdteske	[ "$_ipaddr"     ] && setvar $VAR_IPADDR     "$_ipaddr"
1503247280Sdteske	[ "$_netmask"    ] && setvar $VAR_NETMASK    "$_netmask"
1504247280Sdteske	[ "$_extras"     ] && setvar $VAR_EXTRAS     "$_extras"
1505247280Sdteske
1506247280Sdteske	f_dprintf "Creating struct DEVICE_INFO devinfo_%s" "$dev"
1507247280Sdteske	f_struct_new DEVICE_INFO devinfo_$dev
1508266290Sdteske	$dev set private devinfo_$dev
1509247280Sdteske
1510247280Sdteske	devinfo_$dev set ipaddr    $_ipaddr
1511247280Sdteske	devinfo_$dev set netmask   $_netmask
1512247280Sdteske	devinfo_$dev set extras    $_extras
1513247280Sdteske	devinfo_$dev set use_rtsol $use_rtsol
1514247280Sdteske	devinfo_$dev set use_dhcp  $use_dhcp
1515247280Sdteske
1516247280Sdteske	if [ "$use_dhcp" -o "$_ipaddr" ]; then
1517247280Sdteske		if [ "$use_dhcp" ]; then
1518247280Sdteske			cp="DHCP${extras:+ $extras}"
1519247280Sdteske		else
1520247280Sdteske			cp="inet $_ipaddr netmask $_netmask${extras:+ $extras}"
1521247280Sdteske		fi
1522266290Sdteske		setvar $VAR_IFCONFIG$devname "$cp"
1523247280Sdteske	fi
1524247280Sdteske	[ "$use_rtsol" ] &&
1525247280Sdteske		setvar $VAR_IPV6_ENABLE "YES"
1526247280Sdteske
1527247280Sdteske	[ "$use_dhcp" ] ||
1528247280Sdteske		f_config_resolv # XXX this will do it on the MFS copy
1529247280Sdteske
1530256181Sdteske	return $DIALOG_OK
1531247280Sdteske}
1532247280Sdteske
1533247280Sdteske# f_device_scan_tcp [$var_to_set]
1534247280Sdteske#
1535247280Sdteske# Scan for the first active/configured TCP/IP device. The name of the interface
1536247280Sdteske# is printed to stderr like other dialog(1)-based functions (stdout is reserved
1537247280Sdteske# for dialog(1) interaction) if $var_to_set is missing or NULL. Returns failure
1538247280Sdteske# if no active/configured interface
1539247280Sdteske#
1540247280Sdteskef_device_scan_tcp()
1541247280Sdteske{	
1542247280Sdteske	local __var_to_set="$1" __iface
1543247280Sdteske	for __iface in $( ifconfig -l ); do
1544247280Sdteske		if ifconfig $__iface | awk '
1545247280Sdteske		BEGIN {
1546247280Sdteske			has_inet = has_inet6 = is_ethernet = 0
1547247280Sdteske			is_usable = 1
1548247280Sdteske		}
1549247280Sdteske		( $1 == "status:" && $2 != "active" ) { is_usable = 0; exit }
1550247280Sdteske		( $1 == "inet" ) {
1551247280Sdteske			if ($2 == "0.0.0.0") { is_usable = 0; exit }
1552247280Sdteske			has_inet++
1553247280Sdteske		}
1554247280Sdteske		( $1 == "inet6") { has_inet6++ }
1555247280Sdteske		( $1 == "media:" ) {
1556247280Sdteske			if ($2 != "Ethernet") { is_usable = 0; exit }
1557247280Sdteske			is_ethernet = 1
1558247280Sdteske		}
1559247280Sdteske		END {
1560247280Sdteske			if (!(is_ethernet && (has_inet || has_inet6)))
1561247280Sdteske				is_usable = 0
1562247280Sdteske			exit ! is_usable
1563247280Sdteske		}'; then
1564247280Sdteske			f_interactive &&
1565247280Sdteske				f_show_msg "$msg_using_interface" "$__iface"
1566247280Sdteske			f_dprintf "f_device_scan_tcp found %s" "$__iface"
1567247280Sdteske			if [ "$__var_to_set" ]; then
1568247280Sdteske				setvar "$__var_to_set" "$__iface"
1569247280Sdteske			else
1570247280Sdteske				echo "$__iface" >&2
1571247280Sdteske			fi
1572247280Sdteske			return $SUCCESS
1573247280Sdteske		fi
1574247280Sdteske	done
1575247280Sdteske
1576247280Sdteske	return $FAILURE
1577247280Sdteske}
1578247280Sdteske
1579247280Sdteske# f_device_select_tcp
1580247280Sdteske#
1581247280Sdteske# Prompt the user to select network interface to use for TCP/IP access.
1582247280Sdteske# Variables from variable.subr that can be used to script user input:
1583247280Sdteske#
1584247280Sdteske# 	VAR_NETWORK_DEVICE [Optional]
1585247280Sdteske# 		Either a comma-separated list of network interfaces to try when
1586247280Sdteske# 		setting up network access (e.g., "fxp0,em0") or "ANY" (case-
1587247280Sdteske# 		sensitive) to indicate that the first active and configured
1588247280Sdteske# 		interface is acceptable. If unset, the user is presented with a
1589247280Sdteske# 		menu of all available network interfaces.
1590247280Sdteske#
1591247280Sdteske# Returns success if a valid network interface has been selected.
1592247280Sdteske#
1593247280Sdteskef_device_select_tcp()
1594247280Sdteske{
1595266290Sdteske	local devs dev cnt if network_dev
1596247280Sdteske	f_getvar $VAR_NETWORK_DEVICE network_dev
1597247280Sdteske
1598247280Sdteske	f_dprintf "f_device_select_tcp: %s=[%s]" \
1599247280Sdteske	          VAR_NETWORK_DEVICE "$network_dev"
1600247280Sdteske
1601247280Sdteske	if [ "$network_dev" ]; then
1602247280Sdteske		#
1603247280Sdteske		# This can be set to several types of values. If set to ANY,
1604247280Sdteske		# scan all network devices looking for a valid link, and go
1605247280Sdteske		# with the first device found. Can also be specified as a
1606247280Sdteske		# comma delimited list, with each network device tried in
1607247280Sdteske		# order. Can also be set to a single network device.
1608247280Sdteske		#
1609247280Sdteske		[ "$network_dev" = "ANY" ] && f_device_scan_tcp network_dev
1610247280Sdteske
1611247280Sdteske		while [ "$network_dev" ]; do
1612247280Sdteske			case "$network_dev" in
1613266290Sdteske			*,*) if="${network_dev%%,*}"
1614247280Sdteske			     network_dev="${network_dev#*,}"
1615247280Sdteske			     ;;
1616266290Sdteske			  *) if="$network_dev"
1617247280Sdteske			     network_dev=
1618247280Sdteske			esac
1619247280Sdteske
1620266290Sdteske			f_device_find -1 "$if" $DEVICE_TYPE_NETWORK dev
1621266290Sdteske			f_device_dialog_tcp $dev
1622266290Sdteske			if [ $? -eq $DIALOG_OK ]; then
1623266290Sdteske				setvar $VAR_NETWORK_DEVICE $if
1624266290Sdteske				return $DIALOG_OK
1625247280Sdteske			fi
1626247280Sdteske		done
1627247280Sdteske
1628252795Sdteske		f_interactive && f_show_msg "$msg_no_network_devices"
1629256181Sdteske		return $DIALOG_CANCEL
1630247280Sdteske
1631247280Sdteske	fi # $network_dev
1632247280Sdteske
1633247280Sdteske	f_device_find "" $DEVICE_TYPE_NETWORK devs
1634260678Sdteske	f_count cnt $devs
1635247280Sdteske	dev="${devs%%[$IFS]*}"
1636266290Sdteske	$dev get name if
1637247280Sdteske
1638247280Sdteske	f_quietly f_getvar NETWORK_CONFIGURED # for debugging info
1639247280Sdteske	if ! f_running_as_init &&
1640247280Sdteske	   ! [ "${NETWORK_CONFIGURED+set}" -a "$NETWORK_CONFIGURED" = "NO" ]
1641247280Sdteske	then
1642247280Sdteske		trap 'f_interrupt' SIGINT
1643247280Sdteske		if f_dialog_yesno "$msg_assume_network_is_already_configured"
1644247280Sdteske		then
1645266290Sdteske			setvar $VAR_NETWORK_DEVICE $if
1646256181Sdteske			return $DIALOG_OK
1647247280Sdteske		fi
1648247280Sdteske	fi
1649247280Sdteske
1650247280Sdteske	local retval=$SUCCESS
1651247280Sdteske	if [ ${cnt:=0} -eq 0 ]; then
1652252795Sdteske		f_show_msg "$msg_no_network_devices"
1653256181Sdteske		retval=$DIALOG_CANCEL
1654247280Sdteske	elif [ $cnt -eq 1 ]; then
1655247280Sdteske		f_device_dialog_tcp $dev
1656247280Sdteske		retval=$?
1657266290Sdteske		[ $retval -eq $DIALOG_OK ] && setvar $VAR_NETWORK_DEVICE $if
1658247280Sdteske	else
1659247280Sdteske		local title="$msg_network_interface_information_required"
1660247280Sdteske		local prompt="$msg_please_select_ethernet_device_to_configure"
1661247280Sdteske		local hline="$hline_arrows_tab_enter"
1662247280Sdteske
1663247280Sdteske		dev=$( f_device_menu \
1664247280Sdteske			"$title" "$prompt" "$hline" $DEVICE_TYPE_NETWORK \
1665247280Sdteske			"$NETWORK_DEVICE_HELPFILE" \
1666266290Sdteske			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) ||
1667266290Sdteske			return $DIALOG_CANCEL
1668247280Sdteske
1669247280Sdteske		f_device_dialog_tcp $dev
1670247280Sdteske		retval=$?
1671256181Sdteske		if [ $retval -eq $DIALOG_OK ]; then
1672266290Sdteske			f_struct_copy "$dev" device_network
1673266290Sdteske			setvar $VAR_NETWORK_DEVICE device_network
1674247280Sdteske		else
1675247280Sdteske			f_struct_free device_network
1676247280Sdteske		fi
1677247280Sdteske	fi
1678247280Sdteske
1679247280Sdteske	return $retval
1680247280Sdteske}
1681247280Sdteske
1682247280Sdteske# f_dialog_menu_select_tcp
1683247280Sdteske#
1684247280Sdteske# Like f_dialog_select_tcp() above, but do it from a menu that doesn't care
1685247280Sdteske# about status. In other words, where f_dialog_select_tcp() will not display a
1686247280Sdteske# menu if scripted, this function will always display the menu of available
1687247280Sdteske# network interfaces.
1688247280Sdteske#
1689247280Sdteskef_dialog_menu_select_tcp()
1690247280Sdteske{
1691247280Sdteske	local private use_dhcp name
1692247280Sdteske	NETWORK_CONFIGURED=NO f_device_select_tcp
1693247280Sdteske	if f_struct device_network &&
1694247280Sdteske	   device_network get private private &&
1695247280Sdteske	   f_struct_copy "$private" di &&
1696247280Sdteske	   di get use_dhcp use_dhcp &&
1697247280Sdteske	   [ ! "$use_dhcp" ] &&
1698247280Sdteske	   device_network get name name &&
1699247280Sdteske	   f_yesno "$msg_would_you_like_to_bring_interface_up" "$name"
1700247280Sdteske	then
1701266290Sdteske		if ! f_device_init device_network; then
1702247280Sdteske			f_show_msg "$msg_initialization_of_device_failed" \
1703247280Sdteske			           "$name"
1704247280Sdteske		fi
1705247280Sdteske	fi
1706256181Sdteske	return $DIALOG_OK
1707247280Sdteske}
1708247280Sdteske
1709247280Sdteske############################################################ MAIN
1710247280Sdteske
1711247280Sdteskef_dprintf "%s: Successfully loaded." media/tcpip.subr
1712247280Sdteske
1713247280Sdteskefi # ! $_MEDIA_TCPIP_SUBR
1714