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