1if [ ! "$_MEDIA_TCPIP_SUBR" ]; then _MEDIA_TCPIP_SUBR=1 2# 3# Copyright (c) 2012-2013 Devin Teske 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26# 27# $FreeBSD$ 28# 29############################################################ INCLUDES 30 31BSDCFG_SHARE="/usr/share/bsdconfig" 32. $BSDCFG_SHARE/common.subr || exit 1 33f_dprintf "%s: loading includes..." media/tcpip.subr 34f_include $BSDCFG_SHARE/device.subr 35f_include $BSDCFG_SHARE/dialog.subr 36f_include $BSDCFG_SHARE/struct.subr 37f_include $BSDCFG_SHARE/variable.subr 38 39BSDCFG_LIBE="/usr/libexec/bsdconfig" 40f_include_lang $BSDCFG_LIBE/include/messages.subr 41 42TCP_HELPFILE=$BSDCFG_LIBE/include/tcp.hlp 43NETWORK_DEVICE_HELPFILE=$BSDCFG_LIBE/include/network_device.hlp 44 45############################################################ GLOBALS 46 47# 48# Path to resolv.conf(5). 49# 50: ${RESOLV_CONF:="/etc/resolv.conf"} 51 52# 53# Path to nsswitch.conf(5). 54# 55: ${NSSWITCH_CONF:="/etc/nsswitch.conf"} 56 57# 58# Path to hosts(5) 59# 60: ${ETC_HOSTS:="/etc/hosts"} 61 62# 63# Structure of dhclient.leases(5) lease { ... } entry 64# 65f_struct_define DHCP_LEASE \ 66 interface \ 67 fixed_address \ 68 filename \ 69 server_name \ 70 script \ 71 medium \ 72 host_name \ 73 subnet_mask \ 74 routers \ 75 domain_name_servers \ 76 domain_name \ 77 broadcast_address \ 78 dhcp_lease_time \ 79 dhcp_message_type \ 80 dhcp_server_identifier \ 81 dhcp_renewal_time \ 82 dhcp_rebinding_time \ 83 renew \ 84 rebind \ 85 expire 86 87############################################################ FUNCTIONS 88 89# f_validate_hostname $hostname 90# 91# Returns zero if the given argument (a fully-qualified hostname) is compliant 92# with standards set-forth in RFC's 952 and 1123 of the Network Working Group: 93# 94# RFC 952 - DoD Internet host table specification 95# http://tools.ietf.org/html/rfc952 96# 97# RFC 1123 - Requirements for Internet Hosts - Application and Support 98# http://tools.ietf.org/html/rfc1123 99# 100# See http://en.wikipedia.org/wiki/Hostname for a brief overview. 101# 102# The return status for invalid hostnames is one of: 103# 255 Entire hostname exceeds the maximum length of 255 characters. 104# 63 One or more individual labels within the hostname (separated by 105# dots) exceeds the maximum of 63 characters. 106# 1 One or more individual labels within the hostname contains one 107# or more invalid characters. 108# 2 One or more individual labels within the hostname starts or 109# ends with a hyphen (hyphens are allowed, but a label cannot 110# begin or end with a hyphen). 111# 3 One or more individual labels within the hostname are null. 112# 113# f_dialog_validate_hostname $hostname 114# 115# If the hostname is determined to be invalid, the appropriate error will be 116# displayed using the f_show_msg function. 117# 118f_validate_hostname() 119{ 120 local fqhn="$1" 121 122 # Return error if the hostname exceeds 255 characters 123 [ ${#fqhn} -gt 255 ] && return 255 124 125 local IFS="." # Split on `dot' 126 for label in $fqhn; do 127 # Return error if the label exceeds 63 characters 128 [ ${#label} -gt 63 ] && return 63 129 130 # Return error if the label is null 131 [ "$label" ] || return 3 132 133 # Return error if label begins/ends with dash 134 case "$label" in -*|*-) return 2; esac 135 136 # Return error if the label contains any invalid chars 137 case "$label" in *[!0-9a-zA-Z-]*) return 1; esac 138 done 139 140 return $SUCCESS 141} 142 143# f_inet_atoi $ipv4_address [$var_to_set] 144# 145# Convert an IPv4 address or mask from dotted-quad notation (e.g., `127.0.0.1' 146# or `255.255.255.0') to a 32-bit unsigned integer for the purpose of network 147# and broadcast calculations. For example, one can validate that two addresses 148# are on the same network: 149# 150# f_inet_atoi 1.2.3.4 ip1num 151# f_inet_atoi 1.2.4.5 ip2num 152# f_inet_atoi 255.255.0.0 masknum 153# if [ $(( $ip1num & $masknum )) -eq \ 154# $(( $ip2num & $masknum )) ] 155# then 156# : IP addresses are on same network 157# fi 158# 159# See f_validate_ipaddr() below for an additional example usage, on calculating 160# network and broadcast addresses. 161# 162# If $var_to_set is missing or NULL, the converted IP address is printed to 163# standard output for capturing in a sub-shell (which is less-recommended 164# because of performance degredation; for example, when called in a loop). 165# 166f_inet_atoi() 167{ 168 local __addr="$1" __var_to_set="$2" __num=0 169 if f_validate_ipaddr "$__addr"; then 170 __num=$( IFS=.; set -- $__addr; \ 171 echo $(( ($1 << 24) + ($2 << 16) + ($3 << 8) + $4 )) ) 172 fi 173 if [ "$__var_to_set" ]; then 174 setvar "$__var_to_set" $__num 175 else 176 echo $__num 177 fi 178} 179 180# f_validate_ipaddr $ipaddr [$netmask] 181# 182# Returns zero if the given argument (an IP address) is of the proper format. 183# 184# The return status for invalid IP address is one of: 185# 1 One or more individual octets within the IP address (separated 186# by dots) contains one or more invalid characters. 187# 2 One or more individual octets within the IP address are null 188# and/or missing. 189# 3 One or more individual octets within the IP address exceeds the 190# maximum of 255 (or 2^8, being an octet comprised of 8 bits). 191# 4 The IP address has either too few or too many octets. 192# 193# If a netmask is provided, the IP address is checked further: 194# 195# 5 The IP address must not be the network or broadcast address. 196# 197f_validate_ipaddr() 198{ 199 local ip="$1" mask="$2" 200 201 # Track number of octets for error checking 202 local noctets=0 203 204 local oldIFS="$IFS" 205 local IFS="." # Split on `dot' 206 for octet in $ip; do 207 # Return error if the octet is null 208 [ "$octet" ] || return 2 209 210 # Return error if not a whole integer 211 f_isinteger "$octet" || return 1 212 213 # Return error if not a positive integer 214 [ $octet -ge 0 ] || return 1 215 216 # Return error if the octet exceeds 255 217 [ $octet -gt 255 ] && return 3 218 219 noctets=$(( $noctets + 1 )) 220 done 221 IFS="$oldIFS" 222 223 [ $noctets -eq 4 ] || return 4 224 225 # 226 # The IP address must not be network or broadcast address. 227 # 228 if [ "$mask" ]; then 229 local ipnum masknum netnum bcastnum 230 local max_addr=4294967295 # 255.255.255.255 231 232 f_inet_atoi $ip ipnum 233 f_inet_atoi $mask masknum 234 235 netnum=$(( $ipnum & $masknum )) 236 bcastnum=$(( ($ipnum & $masknum)+$max_addr-$masknum )) 237 238 if [ "$masknum" ] && 239 [ $ipnum -eq $netnum -o $ipnum -eq $bcastnum ] 240 then 241 return 5 242 fi 243 fi 244 245 return $SUCCESS 246} 247 248# f_validate_ipaddr6 $ipv6_addr 249# 250# Returns zero if the given argument (an IPv6 address) is of the proper format. 251# 252# The return status for invalid IP address is one of: 253# 1 One or more individual segments within the IP address 254# (separated by colons) contains one or more invalid characters. 255# Segments must contain only combinations of the characters 0-9, 256# A-F, or a-f. 257# 2 Too many/incorrect null segments. A single null segment is 258# allowed within the IP address (separated by colons) but not 259# allowed at the beginning or end (unless a double-null segment; 260# i.e., "::*" or "*::"). 261# 3 One or more individual segments within the IP address 262# (separated by colons) exceeds the length of 4 hex-digits. 263# 4 The IP address entered has either too few (less than 3), too 264# many (more than 8), or not enough segments, separated by 265# colons. 266# 5* The IPv4 address at the end of the IPv6 address is invalid. 267# * When there is an error with the dotted-quad IPv4 address at the 268# end of the IPv6 address, the return value of 5 is OR'd with a 269# bit-shifted (<< 4) return of f_validate_ipaddr. 270# 271f_validate_ipaddr6() 272{ 273 local ip="${1%\%*}" # removing the interface specification if-present 274 275 local IFS=":" # Split on `colon' 276 set -- $ip: 277 278 # Return error if too many or too few segments 279 # Using 9 as max in case of leading or trailing null spanner 280 [ $# -gt 9 -o $# -lt 3 ] && return 4 281 282 local h="[0-9A-Fa-f]" 283 local nulls=0 nsegments=$# contains_ipv4_segment= 284 285 while [ $# -gt 0 ]; do 286 287 segment="${1%:}" 288 shift 289 290 # 291 # Return error if this segment makes one null too-many. A 292 # single null segment is allowed anywhere in the middle as well 293 # as double null segments are allowed at the beginning or end 294 # (but not both). 295 # 296 if [ ! "$segment" ]; then 297 nulls=$(( $nulls + 1 )) 298 if [ $nulls -eq 3 ]; then 299 # Only valid syntax for 3 nulls is `::' 300 [ "$ip" = "::" ] || return 2 301 elif [ $nulls -eq 2 ]; then 302 # Only valid if begins/ends with `::' 303 case "$ip" in 304 ::*|*::) : fall thru ;; 305 *) return 2 306 esac 307 fi 308 continue 309 fi 310 311 # 312 # Return error if not a valid hexadecimal short 313 # 314 case "$segment" in 315 $h|$h$h|$h$h$h|$h$h$h$h) 316 : valid segment of 1-4 hexadecimal digits 317 ;; 318 *[!0-9A-Fa-f]*) 319 # Segment contains at least one invalid char 320 321 # Return error immediately if not last segment 322 [ $# -eq 0 ] || return 1 323 324 # Otherwise, check for legacy IPv4 notation 325 case "$segment" in 326 *[!0-9.]*) 327 # Segment contains at least one invalid 328 # character even for an IPv4 address 329 return 1 330 esac 331 332 # Return error if not enough segments 333 if [ $nulls -eq 0 ]; then 334 [ $nsegments -eq 7 ] || return 4 335 fi 336 337 contains_ipv4_segment=1 338 339 # Validate the IPv4 address 340 f_validate_ipaddr "$segment" || 341 return $(( 5 | $? << 4 )) 342 ;; 343 *) 344 # Segment characters are all valid but too many 345 return 3 346 esac 347 348 done 349 350 if [ $nulls -eq 1 ]; then 351 # Single null segment cannot be at beginning/end 352 case "$ip" in 353 :*|*:) return 2 354 esac 355 fi 356 357 # 358 # A legacy IPv4 address can span the last two 16-bit segments, 359 # reducing the amount of maximum allowable segments by-one. 360 # 361 maxsegments=8 362 if [ "$contains_ipv4_segment" ]; then 363 maxsegments=7 364 fi 365 366 case $nulls in 367 # Return error if missing segments with no null spanner 368 0) [ $nsegments -eq $maxsegments ] || return 4 ;; 369 # Return error if null spanner with too many segments 370 1) [ $nsegments -le $maxsegments ] || return 4 ;; 371 # Return error if leading/trailing `::' with too many segments 372 2) [ $nsegments -le $(( $maxsegments + 1 )) ] || return 4 ;; 373 esac 374 375 return $SUCCESS 376} 377 378# f_validate_netmask $netmask 379# 380# Returns zero if the given argument (a subnet mask) is of the proper format. 381# 382# The return status for invalid netmask is one of: 383# 1 One or more individual fields within the subnet mask (separated 384# by dots) contains one or more invalid characters. 385# 2 One or more individual fields within the subnet mask are null 386# and/or missing. 387# 3 One or more individual fields within the subnet mask exceeds 388# the maximum of 255 (a full 8-bit register). 389# 4 The subnet mask has either too few or too many fields. 390# 5 One or more individual fields within the subnet mask is an 391# invalid integer (only 0,128,192,224,240,248,252,254,255 are 392# valid integers). 393# 394f_validate_netmask() 395{ 396 local mask="$1" 397 398 # Track number of fields for error checking 399 local nfields=0 400 401 local IFS="." # Split on `dot' 402 for field in $mask; do 403 # Return error if the field is null 404 [ "$field" ] || return 2 405 406 # Return error if not a whole positive integer 407 f_isinteger "$field" || return 1 408 409 # Return error if the field exceeds 255 410 [ $field -gt 255 ] && return 3 411 412 # Return error if the field is an invalid integer 413 case "$field" in 414 0|128|192|224|240|248|252|254|255) : ;; 415 *) return 5 ;; 416 esac 417 418 nfields=$(( $nfields + 1 )) 419 done 420 421 [ $nfields -eq 4 ] || return 4 422} 423 424# f_validate_gateway $gateway $ipaddr $netmask 425# 426# Validate an IPv4 default gateway (aka router) address for a given IP address 427# making sure the two are in the same network (able to ``talk'' to each other). 428# Returns success if $ipaddr and $gateway are in the same network given subnet 429# mask $netmask. 430# 431f_validate_gateway() 432{ 433 local gateway="$1" ipaddr="$2" netmask="$3" 434 local gwnum ipnum masknum 435 436 f_validate_ipaddr "$gateway" "$netmask" || return $FAILURE 437 438 f_inet_atoi "$netmask" masknum 439 f_inet_atoi "$ipaddr" ipnum 440 f_inet_atoi "$gateway" gwnum 441 442 # Gateway must be within set of IPs reachable through interface 443 [ $(( $ipnum & $masknum )) -eq \ 444 $(( $gwnum & $masknum )) ] # Return status 445} 446 447# f_dialog_validate_tcpip $hostname $gateway $nameserver $ipaddr $netmask 448# 449# Returns success if the arguments provided are valid for accessing a TCP/IP 450# network, otherwise returns failure. 451# 452f_dialog_validate_tcpip() 453{ 454 local hostname="$1" gateway="$2" nameserver="$3" 455 local ipaddr="$4" netmask="$5" 456 local ipnum masknum 457 458 if [ ! "$hostname" ]; then 459 f_show_msg "$msg_must_specify_a_host_name_of_some_sort" 460 elif ! f_validate_hostname "$hostname"; then 461 f_show_msg "$msg_invalid_hostname_value" 462 elif [ "$netmask" ] && ! f_validate_netmask "$netmask"; then 463 f_show_msg "$msg_invalid_netmask_value" 464 elif [ "$nameserver" ] && 465 ! f_validate_ipaddr "$nameserver" && 466 ! f_validate_ipaddr6 "$nameserver"; then 467 f_show_msg "$msg_invalid_name_server_ip_address_specified" 468 elif [ "$ipaddr" ] && ! f_validate_ipaddr "$ipaddr" "$netmask"; then 469 f_show_msg "$msg_invalid_ipv4_address" 470 elif [ "$gateway" -a "$gateway" != "NO" ] && 471 ! f_validate_gateway "$gateway" "$ipaddr" "$netmask"; then 472 f_show_msg "$msg_invalid_gateway_ipv4_address_specified" 473 else 474 return $DIALOG_OK 475 fi 476 477 return $DIALOG_CANCEL 478} 479 480# f_ifconfig_inet $interface [$var_to_set] 481# 482# Returns the IPv4 address associated with $interface. If $var_to_set is 483# missing or NULL, the IP address is printed to standard output for capturing 484# in a sub-shell (which is less-recommended because of performance degredation; 485# for example, when called in a loop). 486# 487# This function is a two-parter. Below is the awk(1) portion of the function, 488# afterward is the sh(1) function which utilizes the below awk script. 489# 490f_ifconfig_inet_awk=' 491BEGIN { found = 0 } 492( $1 == "inet" ) \ 493{ 494 print $2 495 found = 1 496 exit 497} 498END { exit ! found } 499' 500f_ifconfig_inet() 501{ 502 local __interface="$1" __var_to_set="$2" 503 if [ "$__var_to_set" ]; then 504 local __ip 505 __ip=$( ifconfig "$__interface" 2> /dev/null | 506 awk "$f_ifconfig_inet_awk" ) 507 setvar "$__var_to_set" "$__ip" 508 else 509 ifconfig "$__interface" 2> /dev/null | 510 awk "$f_ifconfig_inet_awk" 511 fi 512} 513 514# f_ifconfig_inet6 $interface [$var_to_set] 515# 516# Returns the IPv6 address associated with $interface. If $var_to_set is 517# missing or NULL, the IP address is printed to standard output for capturing 518# in a sub-shell (which is less-recommended because of performance degredation; 519# for example, when called in a loop). 520# 521# This function is a two-parter. Below is the awk(1) portion of the function, 522# afterward is the sh(1) function which utilizes the below awk script. 523# 524f_ifconfig_inet6_awk=' 525BEGIN { found = 0 } 526( $1 == "inet6" ) \ 527{ 528 print $2 529 found = 1 530 exit 531} 532END { exit ! found } 533' 534f_ifconfig_inet6() 535{ 536 local __interface="$1" __var_to_set="$2" 537 if [ "$__var_to_set" ]; then 538 local __ip6 539 __ip6=$( ifconfig "$__interface" 2> /dev/null | 540 awk "$f_ifconfig_inet6_awk" ) 541 setvar "$__var_to_set" "$__ip6" 542 else 543 ifconfig "$__interface" 2> /dev/null | 544 awk "$f_ifconfig_inet6_awk" 545 fi 546} 547 548# f_ifconfig_netmask $interface [$var_to_set] 549# 550# Returns the IPv4 subnet mask associated with $interface. If $var_to_set is 551# missing or NULL, the netmask is printed to standard output for capturing in a 552# sub-shell (which is less-recommended because of performance degredation; for 553# example, when called in a loop). 554# 555f_ifconfig_netmask() 556{ 557 local __interface="$1" __var_to_set="$2" __octets 558 __octets=$( ifconfig "$__interface" 2> /dev/null | awk \ 559 ' 560 BEGIN { found = 0 } 561 ( $1 == "inet" ) \ 562 { 563 printf "%s %s %s %s\n", 564 substr($4,3,2), 565 substr($4,5,2), 566 substr($4,7,2), 567 substr($4,9,2) 568 found = 1 569 exit 570 } 571 END { exit ! found } 572 ' ) || return $FAILURE 573 574 local __octet __netmask= 575 for __octet in $__octets; do 576 __netmask="$__netmask.$( printf "%u" "0x$__octet" )" 577 done 578 __netmask="${__netmask#.}" 579 if [ "$__var_to_set" ]; then 580 setvar "$__var_to_set" "$__netmask" 581 else 582 echo $__netmask 583 fi 584} 585 586# f_route_get_default [$var_to_set] 587# 588# Returns the IP address of the currently active default router. If $var_to_set 589# is missing or NULL, the IP address is printed to standard output for 590# capturing in a sub-shell (which is less-recommended because of performance 591# degredation; for example, when called in a loop). 592# 593# This function is a two-parter. Below is the awk(1) portion of the function, 594# afterward is the sh(1) function which utilizes the below awk script. 595# 596f_route_get_default_awk=' 597BEGIN { found = 0 } 598( $1 == "gateway:" ) \ 599{ 600 print $2 601 found = 1 602 exit 603} 604END { exit ! found } 605' 606f_route_get_default() 607{ 608 local __var_to_set="$1" 609 if [ "$__var_to_set" ]; then 610 local __ip 611 __ip=$( route -n get default 2> /dev/null | 612 awk "$f_route_get_default_awk" ) 613 setvar "$__var_to_set" "$__ip" 614 else 615 route -n get default 2> /dev/null | 616 awk "$f_route_get_default_awk" 617 fi 618} 619 620# f_resolv_conf_nameservers [$var_to_set] 621# 622# Returns nameserver(s) configured in resolv.conf(5). If $var_to_set is missing 623# or NULL, the list of nameservers is printed to standard output for capturing 624# in a sub-shell (which is less-recommended because of performance degredation; 625# for example, when called in a loop). 626# 627# This function is a two-parter. Below is the awk(1) portion of the function, 628# afterward is the sh(1) function which utilizes the below awk script. 629# 630f_resolv_conf_nameservers_awk=' 631BEGIN { found = 0 } 632( $1 == "nameserver" ) \ 633{ 634 print $2 635 found = 1 636} 637END { exit ! found } 638' 639f_resolv_conf_nameservers() 640{ 641 local __var_to_set="$1" 642 if [ "$__var_to_set" ]; then 643 local __ns 644 __ns=$( awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \ 645 2> /dev/null ) 646 setvar "$__var_to_set" "$__ns" 647 else 648 awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \ 649 2> /dev/null 650 fi 651} 652 653# f_config_resolv 654# 655# Attempts to configure resolv.conf(5) and ilk. Returns success if able to 656# write the file(s), otherwise returns error status. 657# 658# Variables from variable.subr that are used in configuring resolv.conf(5) are 659# as follows (all of which can be configured automatically through functions 660# like f_dhcp_get_info() or manually): 661# 662# VAR_NAMESERVER 663# The nameserver to add in resolv.conf(5). 664# VAR_DOMAINNAME 665# The domain to configure in resolv.conf(5). Also used in the 666# configuration of hosts(5). 667# VAR_IPADDR 668# The IPv4 address to configure in hosts(5). 669# VAR_IPV6ADDR 670# The IPv6 address to configure in hosts(5). 671# VAR_HOSTNAME 672# The hostname to associate with the IPv4 and/or IPv6 address in 673# hosts(5). 674# 675f_config_resolv() 676{ 677 local cp c6p dp hp 678 679 f_getvar $VAR_NAMESERVER cp 680 if [ "$cp" ]; then 681 case "$RESOLV_CONF" in 682 */*) f_quietly mkdir -p "${RESOLV_CONF%/*}" ;; 683 esac 684 685 # Attempt to create/truncate the file 686 ( :> "$RESOLV_CONF" ) 2> /dev/null || return $FAILURE 687 688 f_getvar $VAR_DOMAINNAME dp && 689 printf "domain\t%s\n" "$dp" >> "$RESOLV_CONF" 690 printf "nameserver\t%s\n" "$cp" >> "$RESOLV_CONF" 691 692 f_dprintf "Wrote out %s" "$RESOLV_CONF" 693 fi 694 695 f_getvar $VAR_DOMAINNAME dp 696 f_getvar $VAR_IPADDR cp 697 f_getvar $VAR_IPV6ADDR c6p 698 f_getvar $VAR_HOSTNAME hp 699 700 # Attempt to create the file if it doesn't already exist 701 if [ ! -e "$ETC_HOSTS" ]; then 702 case "$ETC_HOSTS" in 703 */*) f_quietly mkdir -p "${ETC_HOSTS%/*}" ;; 704 esac 705 706 ( :> "$ETC_HOSTS" ) 2> /dev/null || return $FAILURE 707 fi 708 709 # Scan the file and add ourselves if not already configured 710 awk -v dn="$dp" -v ip4="$cp" -v ip6="$c6p" -v hn="$hp" ' 711 BEGIN { 712 local4found = local6found = 0 713 hn4found = hn6found = h4found = h6found = 0 714 h = ( match(hn, /\./) ? substr(hn, 0, RSTART-1) : "" ) 715 } 716 ($1 == "127.0.0.1") { local4found = 1 } 717 ($1 == "::1") { local6found = 1 } 718 { 719 for (n = 2; n <= NF; n++) 720 { 721 if ( $1 == ip4 ) { 722 if ( $n == h ) h4found = 1 723 if ( $n == hn ) hn4found = 1 724 if ( $n == hn "." ) hn4found = 1 725 } 726 if ( $1 == ip6 ) { 727 if ( $n == h ) h6found = 1 728 if ( $n == hn ) hn6found = 1 729 if ( $n == hn "." ) hn6found = 1 730 } 731 } 732 } 733 END { 734 hosts = FILENAME 735 736 if ( ! local6found ) 737 printf "::1\t\t\tlocalhost%s\n", 738 ( dn ? " localhost." dn : "" ) >> hosts 739 if ( ! local4found ) 740 printf "127.0.0.1\t\tlocalhost%s\n", 741 ( dn ? " localhost." dn : "" ) >> hosts 742 743 if ( ip6 && ! (h6found && hn6found)) 744 { 745 printf "%s\t%s %s\n", ip6, hn, h >> hosts 746 printf "%s\t%s.\n", ip6, hn >> hosts 747 } 748 else if ( ip6 ) 749 { 750 if ( ! h6found ) 751 printf "%s\t%s.\n", ip6, h >> hosts 752 if ( ! hn6found ) 753 printf "%s\t%s\n", ip6, hn >> hosts 754 } 755 756 if ( ip4 && ! (h4found && hn4found)) 757 { 758 printf "%s\t\t%s %s\n", ip4, hn, h >> hosts 759 printf "%s\t\t%s.\n", ip4, hn >> hosts 760 } 761 else if ( ip4 ) 762 { 763 if ( ! h4found ) 764 printf "%s\t\t%s.\n", ip4, h >> hosts 765 if ( ! hn4found ) 766 printf "%s\t\t%s\n", ip4, hn >> hosts 767 } 768 } 769 ' "$ETC_HOSTS" 2> /dev/null || return $FAILURE 770 771 f_dprintf "Wrote out %s" "$ETC_HOSTS" 772 return $SUCCESS 773} 774 775# f_dhcp_parse_leases $leasefile struct_name 776# 777# Parse $leasefile and store the information for the most recent lease in a 778# struct (see struct.subr for additional details) named `struct_name'. See 779# DHCP_LEASE struct definition in the GLOBALS section above. 780# 781f_dhcp_parse_leases() 782{ 783 local leasefile="$1" struct_name="$2" 784 785 [ "$struct_name" ] || return $FAILURE 786 787 if [ ! -e "$leasefile" ]; then 788 f_dprintf "%s: No such file or directory" "$leasefile" 789 return $FAILURE 790 fi 791 792 f_struct "$struct_name" && f_struct_free "$struct_name" 793 f_struct_new DHCP_LEASE "$struct_name" 794 795 eval "$( awk -v struct="$struct_name" ' 796 BEGIN { 797 lease_found = 0 798 keyword_list = " \ 799 interface \ 800 fixed-address \ 801 filename \ 802 server-name \ 803 script \ 804 medium \ 805 " 806 split(keyword_list, keywords, FS) 807 808 time_list = "renew rebind expire" 809 split(time_list, times, FS) 810 811 option_list = " \ 812 host-name \ 813 subnet-mask \ 814 routers \ 815 domain-name-servers \ 816 domain-name \ 817 broadcast-address \ 818 dhcp-lease-time \ 819 dhcp-message-type \ 820 dhcp-server-identifier \ 821 dhcp-renewal-time \ 822 dhcp-rebinding-time \ 823 " 824 split(option_list, options, FS) 825 } 826 function set_value(prop,value) 827 { 828 lease_found = 1 829 gsub(/[^[:alnum:]_]/, "_", prop) 830 sub(/;$/, "", value) 831 sub(/^"/, "", value) 832 sub(/"$/, "", value) 833 sub(/,.*/, "", value) 834 printf "%s set %s \"%s\"\n", struct, prop, value 835 } 836 /^lease {$/, /^}$/ \ 837 { 838 if ( $0 ~ /^lease {$/ ) next 839 if ( $0 ~ /^}$/ ) exit 840 841 for (k in keywords) 842 { 843 keyword = keywords[k] 844 if ( $1 == keyword ) 845 { 846 set_value(keyword, $2) 847 next 848 } 849 } 850 851 for (t in times) 852 { 853 time = times[t] 854 if ( $1 == time ) 855 { 856 set_value(time, $2 " " $3 " " $4) 857 next 858 } 859 } 860 861 if ( $1 != "option" ) next 862 for (o in options) 863 { 864 option = options[o] 865 if ( $2 == option ) 866 { 867 set_value(option, $3) 868 next 869 } 870 } 871 } 872 EXIT { 873 if ( ! lease_found ) 874 { 875 printf "f_struct_free \"%s\"\n", struct 876 print "return $FAILURE" 877 } 878 } 879 ' "$leasefile" )" 880} 881 882# f_dhcp_get_info $interface 883# 884# Parse the dhclient(8) lease database for $interface to obtain all the 885# necessary IPv4 details necessary to communicate on the network. The retrieved 886# information is stored in VAR_IPADDR, VAR_NETMASK, VAR_GATEWAY, and 887# VAR_NAMESERVER. 888# 889# If reading the lease database fails, values are obtained from ifconfig(8) and 890# route(8). If the DHCP lease did not provide a nameserver (or likewise, we 891# were unable to parse the lease database), fall-back to resolv.conf(5) for 892# obtaining the nameserver. Always returns success. 893# 894f_dhcp_get_info() 895{ 896 local interface="$1" cp 897 local leasefile="/var/db/dhclient.leases.$interface" 898 899 # If it fails, do it the old-fashioned way 900 if f_dhcp_parse_leases "$leasefile" lease; then 901 lease get fixed_address $VAR_IPADDR 902 lease get subnet_mask $VAR_NETMASK 903 lease get routers cp 904 setvar $VAR_GATEWAY "${cp%%,*}" 905 lease get domain_name_servers cp 906 setvar $VAR_NAMESERVER "${cp%%,*}" 907 lease get host_name cp && 908 setvar $VAR_HOSTNAME "$cp" 909 f_struct_free lease 910 else 911 # Bah, now we have to get the information from ifconfig 912 if f_debugging; then 913 f_dprintf "DHCP configured interface returns %s" \ 914 "$( ifconfig "$interface" )" 915 fi 916 f_ifconfig_inet "$interface" $VAR_IPADDR 917 f_ifconfig_netmask "$interface" $VAR_NETMASK 918 f_route_get_default $VAR_GATEWAY 919 fi 920 921 # If we didn't get a name server value, hunt for it in resolv.conf 922 local ns 923 if [ -r "$RESOLV_CONF" ] && ! { 924 f_getvar $VAR_NAMESERVER ns || [ "$ns" ] 925 }; then 926 f_resolv_conf_nameservers cp && 927 setvar $VAR_NAMESERVER ${cp%%[$IFS]*} 928 fi 929 930 return $SUCCESS 931} 932 933# f_rtsol_get_info $interface 934# 935# Returns the rtsol-provided IPv6 address associated with $interface. The 936# retrieved IP address is stored in VAR_IPV6ADDR. Always returns success. 937# 938f_rtsol_get_info() 939{ 940 local interface="$1" cp 941 cp=$( ifconfig "$interface" 2> /dev/null | awk \ 942 ' 943 BEGIN { found = 0 } 944 ( $1 == "inet6" ) && ( $2 ~ /^fe80:/ ) \ 945 { 946 print $2 947 found = 1 948 exit 949 } 950 END { exit ! found } 951 ' ) && setvar $VAR_IPV6ADDR "$cp" 952} 953 954# f_host_lookup $host [$var_to_set] 955# 956# Use host(1) to lookup (or reverse) an Internet number from (or to) a name. 957# Multiple answers are returned separated by a single space. If host(1) does 958# not exit cleanly, its full output is provided and the return status is 1. 959# 960# If nsswitch.conf(5) has been configured to query local access first for the 961# `hosts' database, we'll manually check hosts(5) first (preventing host(1) 962# from hanging in the event that DNS goes awry). 963# 964# If $var_to_set is missing or NULL, the list of IP addresses is printed to 965# standard output for capturing in a sub-shell (which is less-recommended 966# because of performance degredation; for example, when called in a loop). 967# 968# The variables from variable.subr used in looking up the host are as follows 969# (which are set manually): 970# 971# VAR_IPV6_ENABLE [Optional] 972# If set to "YES", enables the lookup of IPv6 addresses and IPv4 973# address. IPv6 addresses, if any, will come before IPv4. Note 974# that if nsswitch.conf(5) shows an affinity for "files" for the 975# "host" database and there is a valid entry in hosts(5) for 976# $host, this setting currently has no effect (an IPv4 address 977# can supersede an IPv6 address). By design, hosts(5) overrides 978# any preferential treatment. Otherwise, if this variable is not 979# set, IPv6 addresses will not be used (IPv4 addresses will 980# specifically be requested from DNS). 981# 982# This function is a two-parter. Below is the awk(1) portion of the function, 983# afterward is the sh(1) function which utilizes the below awk script. 984# 985f_host_lookup_awk=' 986BEGIN{ addrs = "" } 987!/^[[:space:]]*(#|$)/ \ 988{ 989 for (n=1; n++ < NF;) if ($n == name) 990 addrs = addrs (addrs ? " " : "") $1 991} 992END { 993 if (addrs) print addrs 994 exit !addrs 995} 996' 997f_host_lookup() 998{ 999 local __host="$1" __var_to_set="$2" 1000 f_dprintf "f_host_lookup: host=[%s]" "$__host" 1001 1002 # If we're configured to look at local files first, do that 1003 if awk '/^hosts:/{exit !($2=="files")}' "$NSSWITCH_CONF"; then 1004 if [ "$__var_to_set" ]; then 1005 local __cp 1006 if __cp=$( awk -v name="$__host" \ 1007 "$f_host_lookup_awk" "$ETC_HOSTS" ) 1008 then 1009 setvar "$__var_to_set" "$__cp" 1010 return $SUCCESS 1011 fi 1012 else 1013 awk -v name="$__host" \ 1014 "$f_host_lookup_awk" "$ETC_HOSTS" && 1015 return $SUCCESS 1016 fi 1017 fi 1018 1019 # 1020 # Fall back to host(1) -- which is further governed by nsswitch.conf(5) 1021 # 1022 1023 local __output __ip6 __addrs= 1024 f_getvar $VAR_IPV6_ENABLE __ip6 1025 1026 # If we have a TCP media type configured, check for an SRV record 1027 local __srvtypes= 1028 { f_quietly f_getvar $VAR_HTTP_PATH || 1029 f_quietly f_getvar $VAR_HTTP_PROXY_PATH 1030 } && __srvtypes="$__srvtypes _http._tcp" 1031 f_quietly f_getvar $VAR_FTP_PATH && __srvtypes="$__srvtypes _ftp._tcp" 1032 f_quietly f_getvar $VAR_NFS_PATH && 1033 __srvtypes="$__srvtypes _nfs._tcp _nfs._udp" 1034 1035 # Calculate wait time as dividend of total time and host(1) invocations 1036 local __host_runs __wait 1037 if [ "$__ip6" = "YES" ]; then 1038 __host_runs=$(( 2 + $( set -- $__srvtypes; echo $# ) )) 1039 else 1040 __host_runs=$(( 1 + $( set -- $__srvtypes; echo $# ) )) 1041 fi 1042 f_getvar $VAR_MEDIA_TIMEOUT __wait 1043 [ "$__wait" ] && __wait="-W $(( $__wait / $__host_runs ))" 1044 1045 # Query SRV types first (1st host response taken as new host to query) 1046 for __type in $__srvtypes; do 1047 if __output=$( 1048 host -t SRV $__wait -- "$__type.$__host" \ 1049 2> /dev/null 1050 ); then 1051 __host=$( echo "$__output" | 1052 awk '/ SRV /{print $NF;exit}' ) 1053 break 1054 fi 1055 done 1056 1057 # Try IPv6 first (if enabled) 1058 if [ "$__ip6" = "YES" ]; then 1059 if ! __output=$( host -t AAAA $__wait -- "$__host" 2>&1 ); then 1060 # An error occurred, display in-full and return error 1061 [ "$__var_to_set" ] && 1062 setvar "$__var_to_set" "$__output" 1063 return $FAILURE 1064 fi 1065 # Add the IPv6 addresses and fall-through to collect IPv4 too 1066 __addrs=$( echo "$__output" | awk '/ address /{print $NF}' ) 1067 fi 1068 1069 # Good ol' IPv4 1070 if ! __output=$( host -t A $__wait -- "$__host" 2>&1 ); then 1071 # An error occurred, display it in-full and return error 1072 [ "$__var_to_set" ] && setvar "$__var_to_set" "$__output" 1073 return $FAILURE 1074 fi 1075 1076 __addrs="$__addrs${__addrs:+ }$( 1077 echo "$__output" | awk '/ address /{print $NF}' )" 1078 if [ "$__var_to_set" ]; then 1079 setvar "$__var_to_set" "$__addrs" 1080 else 1081 echo $__addrs 1082 fi 1083} 1084 1085# f_device_dialog_tcp $device 1086# 1087# This is it - how to get TCP setup values. Prompt the user to edit/confirm the 1088# interface, gateway, nameserver, and hostname settings -- all required for 1089# general TCP/IP access. 1090# 1091# Variables from variable.subr that can be used to sript user input: 1092# 1093# VAR_NO_INET6 1094# If set, prevents asking the user if they would like to use 1095# rtsol(8) to check for an IPv6 router. 1096# VAR_TRY_RTSOL 1097# If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the 1098# user if they would like to try the IPv6 RouTer SOLicitation 1099# utility (rtsol(8)) to get IPv6 information. Ignored if 1100# VAR_NO_INET6 is set. 1101# VAR_TRY_DHCP 1102# If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the 1103# user if they would like to try to acquire IPv4 connection 1104# settings from a DHCP server using dhclient(8). 1105# 1106# VAR_GATEWAY Default gateway to use. 1107# VAR_IPADDR Interface address to assign. 1108# VAR_NETMASK Interface subnet mask. 1109# VAR_EXTRAS Extra interface options to ifconfig(8). 1110# VAR_HOSTNAME Hostname to set. 1111# VAR_DOMAINNAME Domain name to use. 1112# VAR_NAMESERVER DNS nameserver to use when making lookups. 1113# VAR_IPV6ADDR IPv6 interface address. 1114# 1115# In addition, the following variables are used in acquiring network settings 1116# from the user: 1117# 1118# VAR_NONINTERACTIVE 1119# If set (such as when running in a script), prevents asking the 1120# user questions or displaying the usual prompts, etc. 1121# VAR_NETINTERACTIVE 1122# The one exception to VAR_NONINTERACTIVE is VAR_NETINTERACTIVE, 1123# which if set will prompt the user to try RTSOL (unless 1124# VAR_TRY_RTSOL has been set), try DHCP (unless VAR_TRY_DHCP has 1125# been set), and display the network verification dialog. This 1126# allows you to have a mostly non-interactive script that still 1127# prompts for network setup/confirmation. 1128# 1129# After successfull execution, the following variables are set: 1130# 1131# VAR_IFCONFIG + $device (e.g., `ifconfig_em0') 1132# Defines the ifconfig(8) properties specific to $device. 1133# 1134f_device_dialog_tcp() 1135{ 1136 local dev="$1" cp n 1137 local use_dhcp="" use_rtsol="" 1138 local _ipaddr _netmask _extras 1139 1140 [ "$dev" ] || return $DIALOG_CANCEL 1141 1142 # Initialize vars from previous device values 1143 local private 1144 device_$dev get private private 1145 if [ "$private" ] && f_struct "$private"; then 1146 $private get ipaddr _ipaddr 1147 $private get netmask _netmask 1148 $private get extras _extras 1149 $private get use_dhcp use_dhcp 1150 $private get use_rtsol use_rtsol 1151 else # See if there are any defaults 1152 1153 # 1154 # This is a hack so that the dialogs below are interactive in a 1155 # script if we have requested interactive behavior. 1156 # 1157 local old_interactive= 1158 if ! f_interactive && f_netinteractive; then 1159 f_getvar $VAR_NONINTERACTIVE old_interactive 1160 unset $VAR_NONINTERACTIVE 1161 fi 1162 1163 # 1164 # Try a RTSOL scan if such behavior is desired. 1165 # If the variable was configured and is YES, do it. 1166 # If it was configured to anything else, treat it as NO. 1167 # Otherwise, ask the question interactively. 1168 # 1169 local try6 1170 if ! f_isset $VAR_NO_INET6 && { 1171 { f_getvar $VAR_TRY_RTSOL try6 && [ "$try6" = "YES" ]; } || 1172 { 1173 # Only prompt the user when VAR_TRY_RTSOL is unset 1174 ! f_isset $VAR_TRY_RTSOL && 1175 f_dialog_noyes "$msg_try_ipv6_configuration" 1176 } 1177 }; then 1178 local i 1179 1180 f_quietly sysctl net.inet6.ip6.forwarding=0 1181 f_quietly sysctl net.inet6.ip6.accept_rtadv=1 1182 f_quietly ifconfig $dev up 1183 1184 i=$( sysctl -n net.inet6.ip6.dad_count ) 1185 sleep $(( $i + 1 )) 1186 1187 f_quietly mkdir -p /var/run 1188 f_dialog_info "$msg_scanning_for_ra_servers" 1189 if f_quietly rtsol $dev; then 1190 i=$( sysctl -n net.inet6.ip6.dad_count ) 1191 sleep $(( $i + 1 )) 1192 f_rtsol_get_info $dev 1193 use_rtsol=1 1194 else 1195 use_rtsol= 1196 fi 1197 fi 1198 1199 # 1200 # Try a DHCP scan if such behavior is desired. 1201 # If the variable was configured and is YES, do it. 1202 # If it was configured to anything else, treat it as NO. 1203 # Otherwise, ask the question interactively. 1204 # 1205 local try4 1206 if { f_getvar $VAR_TRY_DHCP try4 && [ "$try4" = "YES" ]; } || { 1207 # Only prompt the user when VAR_TRY_DHCP is unset 1208 ! f_isset $VAR_TRY_DHCP && 1209 f_dialog_noyes "$msg_try_dhcp_configuration" 1210 }; then 1211 f_quietly ifconfig $dev delete 1212 f_quietly mkdir -p /var/db 1213 f_quietly mkdir -p /var/run 1214 f_quietly mkdir -p /tmp 1215 1216 local msg="$msg_scanning_for_dhcp_servers" 1217 trap - SIGINT 1218 ( # Execute in sub-shell to allow/catch Ctrl-C 1219 trap 'exit $FAILURE' SIGINT 1220 if [ "$USE_XDIALOG" ]; then 1221 f_quietly dhclient $dev | 1222 f_xdialog_info "$msg" 1223 else 1224 f_dialog_info "$msg" 1225 f_quietly dhclient $dev 1226 fi 1227 ) 1228 local retval=$? 1229 trap 'f_interrupt' SIGINT 1230 if [ $retval -eq $SUCCESS ]; then 1231 f_dhcp_get_info $dev 1232 use_dhcp=1 1233 else 1234 use_dhcp= 1235 fi 1236 fi 1237 1238 # Restore old VAR_NONINTERACTIVE if needed. 1239 [ "$old_interactive" ] && 1240 setvar $VAR_NONINTERACTIVE "$old_interactive" 1241 1242 # Special hack so it doesn't show up oddly in the menu 1243 local gw 1244 if f_getvar $VAR_GATEWAY gw && [ "$gw" = "NO" ]; then 1245 setvar $VAR_GATEWAY "" 1246 fi 1247 1248 # Get old IP address from variable space, if available 1249 if [ ! "$_ipaddr" ]; then 1250 if f_getvar $VAR_IPADDR cp; then 1251 _ipaddr="$cp" 1252 elif f_getvar ${dev}_$VAR_IPADDR cp; then 1253 _ipaddr="$cp" 1254 fi 1255 fi 1256 1257 # Get old netmask from variable space, if available 1258 if [ ! "$_netmask" ]; then 1259 if f_getvar $VAR_NETMASK cp; then 1260 _netmask="$cp" 1261 elif f_getvar ${dev}_$VAR_NETMASK cp; then 1262 _netmask="$cp" 1263 fi 1264 fi 1265 1266 # Get old extras string from variable space, if available 1267 if [ ! "$_extras" ]; then 1268 if f_getvar $VAR_EXTRAS cp; then 1269 _extras="$cp" 1270 elif f_getvar ${dev}_$VAR_EXTRAS cp; then 1271 _extras="$cp" 1272 fi 1273 fi 1274 fi 1275 1276 # Look up values already recorded with the system, or blank the string 1277 # variables ready to accept some new data 1278 local _hostname _gateway _nameserver 1279 f_getvar $VAR_HOSTNAME _hostname 1280 case "$_hostname" in 1281 *.*) : do nothing ;; # Already fully-qualified 1282 *) 1283 f_getvar $VAR_DOMAINNAME cp 1284 [ "$cp" ] && _hostname="$_hostname.$cp" 1285 esac 1286 f_getvar $VAR_GATEWAY _gateway 1287 f_getvar $VAR_NAMESERVER _nameserver 1288 1289 # Re-check variables for initial inheritance before heading into dialog 1290 [ "$_hostname" ] || _hostname="${HOSTNAME:-$( hostname )}" 1291 [ "$_gateway" ] || f_route_get_default _gateway 1292 [ ! "$_nameserver" ] && 1293 f_resolv_conf_nameservers cp && _nameserver=${cp%%[$IFS]*} 1294 [ "$_ipaddr" ] || f_ifconfig_inet $dev _ipaddr 1295 [ "$_netmask" ] || f_ifconfig_netmask $dev _netmask 1296 1297 # If non-interactive, jump over dialog section and into config section 1298 if f_netinteractive || f_interactive || [ ! "$_hostname" ] 1299 then 1300 [ ! "$_hostname" ] && f_interactive && 1301 f_show_msg "$msg_hostname_variable_not_set" 1302 1303 local title=" $msg_network_configuration " 1304 local hline="$hline_alnum_arrows_punc_tab_enter" 1305 local extras_help="$tcplayout_extras_help" 1306 1307 # Modify the help line for PLIP config 1308 [ "${dev#plip}" != "$dev" ] && 1309 extras_help="$tcplayout_extras_help_for_plip" 1310 1311 f_getvar $VAR_IPV6ADDR cp && [ "$cp" ] && 1312 title="$title($msg_ipv6_ready) " 1313 1314 if [ ! "$USE_XDIALOG" ]; then 1315 local prompt="$msg_dialog_mixedform_navigation_help" 1316 # Calculate center position for displaying device label 1317 local devlabel="$msg_configuration_for_interface $dev" 1318 local width=54 1319 local n=$(( $width/2 - (${#devlabel} + 4)/2 - 2 )) 1320 1321 while :; do 1322 cp=$( $DIALOG \ 1323 --title "$title" \ 1324 --backtitle "$DIALOG_BACKTITLE" \ 1325 --hline "$hline" \ 1326 --item-help \ 1327 --ok-label "$msg_ok" \ 1328 --cancel-label "$msg_cancel" \ 1329 --help-button \ 1330 --help-label "$msg_help" \ 1331 --mixedform "$prompt" 16 $width 9 \ 1332 "$msg_host_name_including_domain:" 1 2 \ 1333 "$_hostname" 2 3 45 255 0 \ 1334 "$tcplayout_hostname_help" \ 1335 "$msg_ipv4_gateway:" 3 2 \ 1336 "$_gateway" 4 3 16 15 0 \ 1337 "$tcplayout_gateway_help" \ 1338 "$msg_name_server:" 3 31 \ 1339 "$_nameserver" 4 32 16 15 0 \ 1340 "$tcplayout_nameserver_help" \ 1341 "- $devlabel -" 5 $n "" 0 0 0 0 3 "" \ 1342 "$msg_ipv4_address:" 6 6 \ 1343 "$_ipaddr" 7 7 16 15 0 \ 1344 "$tcplayout_ipaddr_help" \ 1345 "$msg_netmask:" 6 31 \ 1346 "$_netmask" 7 32 16 15 0 \ 1347 "$tcplayout_netmask_help" \ 1348 "$msg_extra_options_to_ifconfig" 8 6 \ 1349 "$_extras" 9 7 41 2048 0 \ 1350 "$extras_help" \ 1351 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) 1352 1353 # --mixed-form always returns 0, we have to 1354 # use the returned data to determine button 1355 if [ ! "$cp" ]; then 1356 # User either chose "Cancel", pressed 1357 # ESC, or blanked every form field 1358 return $DIALOG_CANCEL 1359 else 1360 n=$( echo "$cp" | f_number_of_lines ) 1361 [ $n -eq 1 ] && case "$cp" in HELP*) 1362 # User chose "Help" 1363 f_show_help "$TCP_HELPFILE" 1364 continue 1365 esac 1366 fi 1367 1368 # Turn mixed-form results into env variables 1369 eval "$( echo "$cp" | awk ' 1370 BEGIN { 1371 n = 0 1372 field[++n] = "_hostname" 1373 field[++n] = "_gateway" 1374 field[++n] = "_nameserver" 1375 field[++n] = "_ipaddr" 1376 field[++n] = "_netmask" 1377 field[++n] = "_extras" 1378 nfields = n 1379 n = 0 1380 } 1381 { 1382 gsub(/'\''/, "'\'\\\\\'\''") 1383 sub(/[[:space:]]*$/, "") 1384 value[field[++n]] = $0 1385 } 1386 END { 1387 for ( n = 1; n <= nfields; n++ ) 1388 { 1389 printf "%s='\''%s'\'';\n", 1390 field[n], 1391 value[field[n]] 1392 } 1393 }' )" 1394 1395 f_dialog_validate_tcpip \ 1396 "$_hostname" \ 1397 "$_gateway" \ 1398 "$_nameserver" \ 1399 "$_ipaddr" \ 1400 "$_netmask" \ 1401 && break 1402 done 1403 else 1404 # Xdialog(1) does not support --mixed-form 1405 # Create a persistent menu instead 1406 1407 f_dialog_title "$msg_network_configuration" 1408 local prompt= 1409 1410 while :; do 1411 cp=$( $DIALOG \ 1412 --title "$DIALOG_TITLE" \ 1413 --backtitle "$DIALOG_BACKTITLE" \ 1414 --hline "$hline" \ 1415 --item-help \ 1416 --ok-label "$msg_ok" \ 1417 --cancel-label "$msg_cancel" \ 1418 --help "" \ 1419 --menu "$prompt" 21 60 8 \ 1420 "$msg_accept_continue" "" \ 1421 "$tcplayout_accept_cont_help" \ 1422 "$msg_host_name_including_domain:" \ 1423 "$_hostname" \ 1424 "$tcplayout_hostname_help" \ 1425 "$msg_ipv4_gateway:" "$_gateway" \ 1426 "$tcplayout_gateway_help" \ 1427 "$msg_name_server:" "$_nameserver" \ 1428 "$tcplayout_nameserver_help" \ 1429 "$msg_ipv4_address:" "$_ipaddr" \ 1430 "$tcplayout_ipaddr_help" \ 1431 "$msg_netmask:" "$_netmask" \ 1432 "$tcplayout_netmask_help" \ 1433 "$msg_extra_options_to_ifconfig" \ 1434 "$_extras" "$extras_help" \ 1435 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD 1436 ) 1437 local retval=$? 1438 f_dialog_data_sanitize cp 1439 f_dprintf "retval=%u mtag=[%s]" $retval "$cp" 1440 1441 if [ $retval -eq $DIALOG_HELP ]; then 1442 f_show_help "$TCP_HELPFILE" 1443 continue 1444 elif [ $retval -ne $DIALOG_OK ]; then 1445 f_dialog_title_restore 1446 return $DIALOG_CANCEL 1447 fi 1448 1449 case "$cp" in 1450 "$msg_accept_continue") 1451 f_dialog_validate_tcpip \ 1452 "$_hostname" \ 1453 "$_gateway" \ 1454 "$_nameserver" \ 1455 "$_ipaddr" \ 1456 "$_netmask" \ 1457 && break ;; 1458 "$msg_host_name_including_domain:") 1459 f_dialog_input cp "$cp" "$_hostname" \ 1460 && _hostname="$cp" ;; 1461 "$msg_ipv4_gateway:") 1462 f_dialog_input cp "$cp" "$_gateway" \ 1463 && _gateway="$cp" ;; 1464 "$msg_name_server:") 1465 f_dialog_input cp "$cp" "$_nameserver" \ 1466 && _nameserver="$cp" ;; 1467 "$msg_ipv4_address:") 1468 f_dialog_input cp "$cp" "$_ipaddr" \ 1469 && _ipaddr="$cp" ;; 1470 "$msg_netmask:") 1471 f_dialog_input cp "$cp" "$_netmask" \ 1472 && _netmask="$cp" ;; 1473 "$msg_extra_options_to_ifconfig") 1474 f_dialog_input cp "$cp" "$_extras" \ 1475 && _extras="$cp" ;; 1476 esac 1477 done 1478 1479 f_dialog_title_restore 1480 1481 fi # XDIALOG 1482 1483 fi # interactive 1484 1485 # We actually need to inform the rest of bsdconfig about this 1486 # data now if the user hasn't selected cancel. 1487 1488 if [ "$_hostname" ]; then 1489 setvar $VAR_HOSTNAME "$_hostname" 1490 f_quietly hostname "$_hostname" 1491 case "$_hostname" in 1492 *.*) setvar $VAR_DOMAINNAME "${_hostname#*.}" ;; 1493 esac 1494 fi 1495 [ "$_gateway" ] && setvar $VAR_GATEWAY "$_gateway" 1496 [ "$_nameserver" ] && setvar $VAR_NAMESERVER "$_nameserver" 1497 [ "$_ipaddr" ] && setvar $VAR_IPADDR "$_ipaddr" 1498 [ "$_netmask" ] && setvar $VAR_NETMASK "$_netmask" 1499 [ "$_extras" ] && setvar $VAR_EXTRAS "$_extras" 1500 1501 f_dprintf "Creating struct DEVICE_INFO devinfo_%s" "$dev" 1502 f_struct_new DEVICE_INFO devinfo_$dev 1503 device_$dev set private devinfo_$dev 1504 1505 devinfo_$dev set ipaddr $_ipaddr 1506 devinfo_$dev set netmask $_netmask 1507 devinfo_$dev set extras $_extras 1508 devinfo_$dev set use_rtsol $use_rtsol 1509 devinfo_$dev set use_dhcp $use_dhcp 1510 1511 if [ "$use_dhcp" -o "$_ipaddr" ]; then 1512 if [ "$use_dhcp" ]; then 1513 cp="DHCP${extras:+ $extras}" 1514 else 1515 cp="inet $_ipaddr netmask $_netmask${extras:+ $extras}" 1516 fi 1517 setvar $VAR_IFCONFIG$dev "$cp" 1518 fi 1519 [ "$use_rtsol" ] && 1520 setvar $VAR_IPV6_ENABLE "YES" 1521 1522 [ "$use_dhcp" ] || 1523 f_config_resolv # XXX this will do it on the MFS copy 1524 1525 return $DIALOG_OK 1526} 1527 1528# f_device_scan_tcp [$var_to_set] 1529# 1530# Scan for the first active/configured TCP/IP device. The name of the interface 1531# is printed to stderr like other dialog(1)-based functions (stdout is reserved 1532# for dialog(1) interaction) if $var_to_set is missing or NULL. Returns failure 1533# if no active/configured interface 1534# 1535f_device_scan_tcp() 1536{ 1537 local __var_to_set="$1" __iface 1538 for __iface in $( ifconfig -l ); do 1539 if ifconfig $__iface | awk ' 1540 BEGIN { 1541 has_inet = has_inet6 = is_ethernet = 0 1542 is_usable = 1 1543 } 1544 ( $1 == "status:" && $2 != "active" ) { is_usable = 0; exit } 1545 ( $1 == "inet" ) { 1546 if ($2 == "0.0.0.0") { is_usable = 0; exit } 1547 has_inet++ 1548 } 1549 ( $1 == "inet6") { has_inet6++ } 1550 ( $1 == "media:" ) { 1551 if ($2 != "Ethernet") { is_usable = 0; exit } 1552 is_ethernet = 1 1553 } 1554 END { 1555 if (!(is_ethernet && (has_inet || has_inet6))) 1556 is_usable = 0 1557 exit ! is_usable 1558 }'; then 1559 f_interactive && 1560 f_show_msg "$msg_using_interface" "$__iface" 1561 f_dprintf "f_device_scan_tcp found %s" "$__iface" 1562 if [ "$__var_to_set" ]; then 1563 setvar "$__var_to_set" "$__iface" 1564 else 1565 echo "$__iface" >&2 1566 fi 1567 return $SUCCESS 1568 fi 1569 done 1570 1571 return $FAILURE 1572} 1573 1574# f_device_select_tcp 1575# 1576# Prompt the user to select network interface to use for TCP/IP access. 1577# Variables from variable.subr that can be used to script user input: 1578# 1579# VAR_NETWORK_DEVICE [Optional] 1580# Either a comma-separated list of network interfaces to try when 1581# setting up network access (e.g., "fxp0,em0") or "ANY" (case- 1582# sensitive) to indicate that the first active and configured 1583# interface is acceptable. If unset, the user is presented with a 1584# menu of all available network interfaces. 1585# 1586# Returns success if a valid network interface has been selected. 1587# 1588f_device_select_tcp() 1589{ 1590 local devs dev cnt network_dev 1591 f_getvar $VAR_NETWORK_DEVICE network_dev 1592 1593 f_dprintf "f_device_select_tcp: %s=[%s]" \ 1594 VAR_NETWORK_DEVICE "$network_dev" 1595 1596 if [ "$network_dev" ]; then 1597 # 1598 # This can be set to several types of values. If set to ANY, 1599 # scan all network devices looking for a valid link, and go 1600 # with the first device found. Can also be specified as a 1601 # comma delimited list, with each network device tried in 1602 # order. Can also be set to a single network device. 1603 # 1604 [ "$network_dev" = "ANY" ] && f_device_scan_tcp network_dev 1605 1606 while [ "$network_dev" ]; do 1607 case "$network_dev" in 1608 *,*) dev="${network_dev%%,*}" 1609 network_dev="${network_dev#*,}" 1610 ;; 1611 *) dev="$network_dev" 1612 network_dev= 1613 esac 1614 1615 f_device_find "$dev" $DEVICE_TYPE_NETWORK devs 1616 cnt=$( set -- $devs; echo $# ) 1617 1618 if [ ${cnt:=0} -gt 0 ]; then 1619 dev="${devs%%[$IFS]*}" 1620 f_device_dialog_tcp $dev 1621 if [ $? -eq $DIALOG_OK ]; then 1622 setvar $VAR_NETWORK_DEVICE $dev 1623 return $DIALOG_OK 1624 fi 1625 fi 1626 done 1627 1628 f_interactive && f_show_msg "$msg_no_network_devices" 1629 return $DIALOG_CANCEL 1630 1631 fi # $network_dev 1632 1633 f_device_find "" $DEVICE_TYPE_NETWORK devs 1634 cnt=$( set -- $devs; echo $# ) 1635 dev="${devs%%[$IFS]*}" 1636 1637 f_quietly f_getvar NETWORK_CONFIGURED # for debugging info 1638 if ! f_running_as_init && 1639 ! [ "${NETWORK_CONFIGURED+set}" -a "$NETWORK_CONFIGURED" = "NO" ] 1640 then 1641 trap 'f_interrupt' SIGINT 1642 if f_dialog_yesno "$msg_assume_network_is_already_configured" 1643 then 1644 setvar $VAR_NETWORK_DEVICE $dev 1645 return $DIALOG_OK 1646 fi 1647 fi 1648 1649 local retval=$SUCCESS 1650 if [ ${cnt:=0} -eq 0 ]; then 1651 f_show_msg "$msg_no_network_devices" 1652 retval=$DIALOG_CANCEL 1653 elif [ $cnt -eq 1 ]; then 1654 f_device_dialog_tcp $dev 1655 retval=$? 1656 [ $retval -eq $DIALOG_OK ] && setvar $VAR_NETWORK_DEVICE $dev 1657 else 1658 local title="$msg_network_interface_information_required" 1659 local prompt="$msg_please_select_ethernet_device_to_configure" 1660 local hline="$hline_arrows_tab_enter" 1661 1662 dev=$( f_device_menu \ 1663 "$title" "$prompt" "$hline" $DEVICE_TYPE_NETWORK \ 1664 "$NETWORK_DEVICE_HELPFILE" \ 1665 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) 1666 retval=$? 1667 [ "$dev" ] || return $DIALOG_CANCEL 1668 1669 f_device_find "$dev" $DEVICE_TYPE_NETWORK devs 1670 [ "$devs" ] || return $DIALOG_CANCEL 1671 dev="${devs%%[$IFS]*}" 1672 1673 f_device_dialog_tcp $dev 1674 retval=$? 1675 if [ $retval -eq $DIALOG_OK ]; then 1676 f_struct_copy device_$dev device_network 1677 setvar $VAR_NETWORK_DEVICE network 1678 else 1679 f_struct_free device_network 1680 fi 1681 fi 1682 1683 return $retval 1684} 1685 1686# f_dialog_menu_select_tcp 1687# 1688# Like f_dialog_select_tcp() above, but do it from a menu that doesn't care 1689# about status. In other words, where f_dialog_select_tcp() will not display a 1690# menu if scripted, this function will always display the menu of available 1691# network interfaces. 1692# 1693f_dialog_menu_select_tcp() 1694{ 1695 local private use_dhcp name 1696 NETWORK_CONFIGURED=NO f_device_select_tcp 1697 if f_struct device_network && 1698 device_network get private private && 1699 f_struct_copy "$private" di && 1700 di get use_dhcp use_dhcp && 1701 [ ! "$use_dhcp" ] && 1702 device_network get name name && 1703 f_yesno "$msg_would_you_like_to_bring_interface_up" "$name" 1704 then 1705 if ! f_device_init network; then 1706 f_show_msg "$msg_initialization_of_device_failed" \ 1707 "$name" 1708 fi 1709 fi 1710 return $DIALOG_OK 1711} 1712 1713############################################################ MAIN 1714 1715f_dprintf "%s: Successfully loaded." media/tcpip.subr 1716 1717fi # ! $_MEDIA_TCPIP_SUBR 1718