1if [ ! "$_MEDIA_HTTPPROXY_SUBR" ]; then _MEDIA_HTTPPROXY_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/httpproxy.subr 33f_include $BSDCFG_SHARE/dialog.subr 34f_include $BSDCFG_SHARE/media/tcpip.subr 35f_include $BSDCFG_SHARE/variable.subr 36 37BSDCFG_LIBE="/usr/libexec/bsdconfig" 38f_include_lang $BSDCFG_LIBE/include/messages.subr 39 40############################################################ FUNCTIONS 41 42# f_media_set_http_proxy 43# 44# Return success if we both found and set the media type to be an ftp server, 45# accessed via http proxy. 46# 47# Variables from variable.subr that can be used to script user input: 48# 49# VAR_HTTP_PROXY 50# HTTP Proxy server to use. Valid examples include: 51# myhost 52# somename:3128 53# 192.168.2.3 54# [::1]:8080 55# The default port if not specified is 3128. 56# 57# Variables from variable.subr that are set after successful execution include 58# the following: 59# 60# VAR_HTTP_PROXY_HOST The host portion of VAR_HTTP_PROXY. 61# VAR_HTTP_PROXY_PORT The TCP port parsed from VAR_HTTP_PROXY. 62# 63# See also f_media_set_ftp() for additional variables. 64# 65f_media_set_http_proxy() 66{ 67 FTP_SKIP_RESOLV=1 f_media_set_ftp || return $FAILURE 68 69 f_variable_get_value $VAR_HTTP_PROXY \ 70 "$msg_please_enter_the_address_of_the_http_proxy" 71 72 local proxy 73 f_getvar $VAR_HTTP_PROXY proxy 74 [ "$proxy" ] || return $FAILURE 75 76 local hostname="$proxy" port=3128 77 case "$hostname" in 78 # 79 # The order in-which the below individual cases appear is important! 80 # 81 "["*"]":*) # IPv6 address with port 82 f_dprintf "Looks like an IPv6 addr with port: %s" "$hostname" 83 hostname="${hostname#\[}" 84 port="${hostname#*\]:}" 85 port="${port%%[!0-9]*}" 86 hostname="${hostname%%\]:*}" 87 ;; 88 "["*"]") # IPv6 address 89 f_dprintf "Looks like an IPv6 addr: %s" "$hostname" 90 hostname="${hostname#\[}" 91 hostname="${hostname%\]}" 92 ;; 93 # 94 # ^^^ IPv6 above / DNS Name or IPv4 below vvv 95 # 96 *:*) # DNS name or IPv4 address with port 97 f_dprintf "Looks like a DNS name or IPv4 addr with port: %s" \ 98 "$hostname" 99 port="${hostname#*:}" 100 hostname="${hostname%%:*}" 101 ;; 102 *) # DNS name or IPv4 address 103 f_dprintf "Looks like a DNS name or IPv4 addr: %s" "$hostname" 104 : leave hostname as-is 105 esac 106 107 setvar $VAR_HTTP_PROXY_HOST "$hostname" 108 setvar $VAR_HTTP_PROXY_PORT "$port" 109 110 if f_debugging; then 111 f_dprintf "VAR_FTP_PATH : %s" "$( f_getvar $VAR_FTP_PATH )" 112 f_dprintf "VAR_HTTP_PROXY_HOST, _PORT: %s:%s" \ 113 "$( f_getvar $VAR_HTTP_PROXY_HOST )" \ 114 "$( f_getvar $VAR_HTTP_PROXY_PORT )" 115 fi 116 117 # media device has been set by f_media_set_ftp(), overwrite partly: 118 device_media set type $DEVICE_TYPE_HTTP_PROXY 119 device_media set init f_media_init_http_proxy 120 device_media set get f_media_get_http_proxy 121 device_media unset shutdown 122 123 return $SUCCESS 124} 125 126# f_http_proxy_check_access [$connect_only] 127# 128# Return success if able list a remote FTP directory via HTTP proxy. If 129# $connect_only is present and non-null, then returns success if a connection 130# can be made. Variables from variable.subr that can be used to script user 131# input: 132# 133# VAR_HTTP_PROXY_HOST 134# The HTTP proxy server host name, IPv4 address or IPv6 address. 135# Valid examples include: 136# myhost 137# 192.168.2.3 138# ::1 139# VAR_HTTP_PROXY_PORT 140# The TCP port to connect to when communicating with the HTTP 141# proxy server. 142# VAR_HTTP_PROXY_PATH 143# The FTP URL sent to the HTTP proxy server. Unused if 144# $connect_only is present and non-NULL. 145# 146f_http_proxy_check_access() 147{ 148 local connect_only="$1" hosts= 149 150 local proxy_host proxy_port 151 f_getvar $VAR_HTTP_PROXY_HOST proxy_host 152 f_getvar $VAR_HTTP_PROXY_PORT proxy_port 153 154 if ! { 155 f_validate_ipaddr "$proxy_host" || 156 f_validate_ipaddr6 "$proxy_host" || 157 { 158 f_dprintf "%s: Looking up hostname, %s, using host(1)" \ 159 "f_http_proxy_check_access" "$proxy_host" 160 f_host_lookup "$proxy_host" hosts 161 } 162 }; then 163 # All the above validations failed 164 [ "$hosts" ] && f_dialog_msgbox "$hosts" 165 unset $VAR_HTTP_PROXY_HOST 166 return $FAILURE 167 elif [ ! "$hosts" ]; then 168 # One of the first two validations passed 169 hosts="$proxy_host" 170 fi 171 172 local host connected= 173 for host in $hosts; do 174 f_quietly nc -nz "$host" "$proxy_port" || continue 175 connected=1; break 176 done 177 if [ ! "$connected" ]; then 178 f_show_msg "$msg_couldnt_connect_to_proxy %s:%s" \ 179 "$proxy_host" "$proxy_port" 180 unset $VAR_HTTP_PROXY_HOST 181 return $FAILURE 182 fi 183 [ "$connect_only" ] && return $SUCCESS 184 185 # 186 # Some proxies fetch files with certain extensions in "ascii mode" 187 # instead of "binary mode" for FTP. The FTP server then translates all 188 # LF to CRLF. 189 # 190 # You can force Squid to use binary mode by appending ";type=i" to the 191 # URL, which is what sysinstall(8) has traditionally done. 192 # 193 194 local proxy_path 195 f_getvar $VAR_HTTP_PROXY_PATH proxy_path 196 f_show_info "$msg_checking_access_to" "$proxy_path" 197 198 local rx 199 if ! rx=$( 200 printf "GET %s/ HTTP/1.0\r\n\r\n" "${proxy_path%/}" | 201 nc -n "$host" "$proxy_port" 202 ); then 203 f_show_msg "$msg_couldnt_connect_to_proxy %s:%s" \ 204 "$proxy_host" "$proxy_port" 205 unset $VAR_HTTP_PROXY_HOST 206 return $FAILURE 207 fi 208 209 local hdr 210 hdr=$( echo "$rx" | awk '/^\r$/{exit}{print}' ) 211 212 local http_found=$FAILURE 213 if echo "$hdr" | awk ' 214 BEGIN { found = 0 } 215 /^HTTP.... 200 / { 216 found = 1 217 exit 218 } 219 END { exit ! found } 220 '; then 221 http_found=$SUCCESS 222 fi 223 224 # 225 # Scan the headers of the response 226 # this is extremely quick'n dity 227 # 228 229 unset $VAR_HTTP_FTP_MODE 230 if echo "$hdr" | awk ' 231 BEGIN { found = 0 } 232 { 233 if (!match($0, /^Server: /)) next 234 found = ( substr($0, 9, 5) ~ /[Ss]quid/ ) 235 } 236 END { exit ! found } 237 '; then 238 setvar $VAR_HTTP_FTP_MODE ";type=i" 239 else 240 setvar $VAR_HTTP_FTP_MODE "" 241 fi 242 243 return $http_found 244} 245 246# f_media_init_http_proxy $device 247# 248# Initializes the HTTP Proxy media device. Returns success if able to confirm 249# the existence of at least one known FTP server release path via HTTP proxy 250# using f_http_proxy_check_access(), above. 251# 252# Variables from variable.subr that can be used to script user input: 253# 254# VAR_HTTP_PROXY_HOST 255# The HTTP proxy server to connect to. Usually set by having 256# f_media_set_http_proxy() parse VAR_HTTP_PROXY. Must be set. 257# Also see f_http_proxy_check_access() for additional variables. 258# VAR_RELNAME 259# Usually set to `uname -r' but can be overridden. 260# VAR_FTP_PATH 261# The FTP URL to send to the HTTP proxy server. Usually set by 262# calling f_media_set_ftp(). 263# 264# Meanwhile, after successful execution, the following variables (also from 265# variable.subr) are set: 266# 267# VAR_HTTP_PROXY_PATH 268# The [possibly] adjusted VAR_FTP_PATH that was found to contain 269# a valid FreeBSD repository. 270# 271f_media_init_http_proxy() 272{ 273 local dev="$1" 274 f_dprintf "Init routine called for HTTP Proxy device. dev=[%s]" "$dev" 275 276 # 277 # First verify access 278 # 279 local connect_only=1 280 f_http_proxy_check_access $connect_only 281 282 local proxy_host 283 f_getvar $VAR_HTTP_PROXY_HOST proxy_host 284 while [ ! "$proxy_host" ]; do 285 f_media_set_http_proxy || return $FAILURE 286 f_http_proxy_check_access $connect_only 287 f_getvar $VAR_HTTP_PROXY_HOST proxy_host 288 done 289 290 local rel proxy_path http_found=$FAILURE 291 while :; do 292 # 293 # If the release is specified as "__RELEASE" or "any", then 294 # just assume that the path the user gave is ok. 295 # 296 f_getvar $VAR_RELNAME rel 297 f_dprintf "f_media_init_http_proxy: rel=[%s]" "$rel" 298 299 case "$rel" in 300 __RELEASE|any) 301 f_getvar $VAR_FTP_PATH $VAR_HTTP_PROXY_PATH 302 f_http_proxy_check_access 303 http_found=$? 304 ;; 305 *) 306 local fdir fp 307 f_getvar $VAR_FTP_PATH%/ fp 308 for fdir in $FTP_DIRS; do 309 setvar $VAR_HTTP_PROXY_PATH "$fp/$fdir/$rel" 310 if f_http_proxy_check_access; then 311 http_found=$SUCCESS 312 break 313 fi 314 done 315 esac 316 317 [ $http_found -eq $SUCCESS ] && break 318 319 f_getvar $VAR_HTTP_PROXY_PATH proxy_path 320 f_show_msg "$msg_please_check_the_url_and_try_again" \ 321 "$proxy_path" 322 323 unset $VAR_HTTP_PROXY_PATH 324 f_media_set_http_proxy || break 325 done 326 327 return $http_found 328} 329 330# f_media_get_http_proxy $device $file [$probe_type] 331# 332# Returns data from $file on an FTP server via HTTP proxy using nc(1). Please 333# note that $device is unused but must be present (even if null). Information 334# is instead gathered from the environment. If $probe_type is both present and 335# non-NULL, this function exits after receiving the HTTP header response from 336# the proxy server (if the HTTP response code is 200, success is returned; 337# otherwise failure). If $probe_type is equal to $PROBE_SIZE, prints the 338# content-length in bytes from the response (or -1 if not found) to standard- 339# out. 340# 341# The variables used to configure the connection are as follows (all of which 342# are configured by f_media_set_http_proxy above): 343# 344# VAR_HTTP_PROXY_HOST 345# HTTP proxy host to connect. Can be an IPv4 address, IPv6 346# address, or DNS hostname of your choice. 347# VAR_HTTP_PROXY_PORT 348# TCP port to connect on; see f_media_set_http_proxy above. 349# VAR_HTTP_PROXY_PATH 350# URL (including "ftp://" protocol-prefix) of FTP directory to 351# use as a prefix when requesting $file via HTTP proxy. 352# 353# See variable.subr for additional information. 354# 355# Example usage: 356# f_media_set_http_proxy 357# f_media_get_http_proxy media $file 358# 359f_media_get_http_proxy() 360{ 361 local dev="$1" file="$2" probe_type="$3" hosts= 362 363 f_dprintf "f_media_get_http_proxy: dev=[%s] file=[%s] probe_type=%s" \ 364 "$dev" "$file" "$probe_type" 365 366 local proxy_host proxy_port 367 f_getvar $VAR_HTTP_PROXY_HOST proxy_host 368 f_getvar $VAR_HTTP_PROXY_PORT proxy_port 369 370 if ! { 371 f_validate_ipaddr "$proxy_host" || 372 f_validate_ipaddr6 "$proxy_host" || 373 { 374 f_dprintf "%s: Looking up hostname, %s, using host(1)" \ 375 "f_media_get_http_proxy" "$proxy_host" 376 f_host_lookup "$proxy_host" hosts 377 } 378 }; then 379 # All the above validations failed 380 [ "$hosts" ] && f_dialog_msgbox "$hosts" 381 return $FAILURE 382 elif [ ! "$hosts" ]; then 383 # One of the first two validations passed 384 hosts="$proxy_host" 385 fi 386 387 local host connected= 388 for host in $hosts; do 389 f_quietly nc -nz "$host" "$proxy_port" || continue 390 connected=1; break 391 done 392 if [ ! "$connected" ]; then 393 f_show_msg "$msg_couldnt_connect_to_proxy %s:%s" \ 394 "$proxy_host" "$proxy_port" 395 return $FAILURE 396 fi 397 398 local proxy_path mode 399 f_getvar $VAR_HTTP_PROXY_PATH%/ proxy_path 400 f_getvar $VAR_HTTP_FTP_MODE mode 401 local url="$proxy_path/$file$mode" rx 402 403 f_dprintf "sending http request for: %s" "$url" 404 printf "GET %s HTTP/1.0\r\n\r\n" "$url" | nc -n "$host" "$proxy_port" | 405 ( 406 # 407 # scan the headers of the response 408 # this is extremely quick'n dirty 409 # 410 411 rv=0 length=-1 412 while read LINE; do 413 case "$LINE" in 414 HTTP*) 415 f_dprintf "received response: %s" "$LINE" 416 set -- $LINE; rv=$2 417 f_isinteger "$rv" || rv=0 418 ;; 419 "Content-Length: "*) 420 length="${LINE% 421}" 422 length="${length#Content-Length: }" 423 f_dprintf "received content-length: %s" \ 424 "$length" 425 ;; 426 *) 427 [ "${LINE% 428}" ] || break # End of headers 429 esac 430 done 431 432 [ $rv -ge 500 ] && exit 5 433 [ $rv -eq 404 ] && exit 44 434 [ $rv -ge 400 ] && exit 4 435 [ $rv -ge 300 ] && exit 3 436 [ $rv -eq 200 ] || exit $FAILURE 437 438 if [ ! "$probe_type" ]; then 439 cat # output the rest ``as-is'' 440 elif [ "$probe_type" = "$PROBE_SIZE" ]; then 441 f_isinteger "$length" || length=-1 442 echo "$length" 443 fi 444 exit 200 445 ) 446 local retval=$? 447 [ $retval -eq 200 ] && return $SUCCESS 448 [ "$probe_type" ] && return $FAILURE 449 450 case "$retval" in 451 5) f_show_msg "$msg_server_error_when_requesting_url" "$url" ;; 452 44) f_show_msg "$msg_url_was_not_found" "$url" ;; 453 4) f_show_msg "$msg_client_error" ;; 454 *) f_show_msg "$msg_error_when_requesting_url" "$url" ;; 455 esac 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD 456 return $FAILURE 457} 458 459############################################################ MAIN 460 461f_dprintf "%s: Successfully loaded." media/httpproxy.subr 462 463fi # ! $_MEDIA_HTTPPROXY_SUBR 464