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