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