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