]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/bsdconfig/share/media/httpproxy.subr
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / bsdconfig / share / media / httpproxy.subr
1 if [ ! "$_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
31 BSDCFG_SHARE="/usr/share/bsdconfig"
32 . $BSDCFG_SHARE/common.subr || exit 1
33 f_dprintf "%s: loading includes..." media/httpproxy.subr
34 f_include $BSDCFG_SHARE/dialog.subr
35 f_include $BSDCFG_SHARE/media/ftp.subr
36 f_include $BSDCFG_SHARE/media/tcpip.subr
37 f_include $BSDCFG_SHARE/variable.subr
38
39 BSDCFG_LIBE="/usr/libexec/bsdconfig"
40 f_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 #
67 f_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 #
148 f_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 #
273 f_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 #
361 f_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%\r}"
423                                 length="${length#Content-Length: }"
424                                 f_dprintf "received content-length: %s" \
425                                           "$length"
426                                 ;;
427                         *)
428                                 [ "${LINE%\r}" ] || 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
456         return $FAILURE
457 }
458
459 ############################################################ MAIN
460
461 f_dprintf "%s: Successfully loaded." media/httpproxy.subr
462
463 fi # ! $_MEDIA_HTTPPROXY_SUBR