Home | History | Annotate | Download | only in scripts
      1 #! /bin/sh
      2 ## Web proxy, following the grand tradition of Web things being handled by
      3 ## gross scripts.  Uses netcat to listen on a high port [default 8000],
      4 ## picks apart requests and sends them on to the right place.  Point this
      5 ## at the browser client machine you'll be coming from [to limit access to
      6 ## only it], and point the browser's concept of an HTTP proxy to the
      7 ## machine running this.  Takes a single argument of the client that will
      8 ## be using it, and rejects connections from elsewhere.  LOGS the queries
      9 ## to a configurable logfile, which can be an interesting read later on!
     10 ## If the argument is "reset", the listener and logfile are cleaned up.
     11 ##
     12 ## This works surprisingly fast and well, for a shell script, although may
     13 ## randomly fail when hammered by a browser that tries to open several
     14 ## connections at once.  Drop the "maximum connections" in your browser if
     15 ## this is a problem.
     16 ##
     17 ## A more degenerate case of this, or preferably a small C program that
     18 ## does the same thing under inetd, could handle a small site's worth of
     19 ## proxy queries.  Given the way browsers are evolving, proxies like this
     20 ## can play an important role in protecting your own privacy.
     21 ##
     22 ## If you grabbed this in ASCII mode, search down for "eew" and make sure
     23 ## the embedded-CR check is intact, or requests might hang.
     24 ##
     25 ## Doesn't handle POST forms.  Who cares, if you're just watching HTTV?
     26 ## Dumbness here has a highly desirable side effect: it only sends the first
     27 ## GET line, since that's all you really ever need to send, and suppresses
     28 ## the other somewhat revealing trash that most browsers insist on sending.
     29 
     30 # set these as you wish: proxy port...
     31 PORT=8000
     32 # logfile spec: a real file or /dev/null if you don't care
     33 LFILE=${0}.log
     34 # optional: where to dump connect info, so you can see if anything went wrong
     35 # CFILE=${0}.conn
     36 # optional extra args to the listener "nc", for instance "-s inside-net-addr"
     37 # XNC=''
     38 
     39 # functionality switch has to be done fast, so the next listener can start
     40 # prelaunch check: if no current client and no args, bail.
     41 case "${1}${CLIENT}" in
     42   "")
     43     echo needs client hostname
     44     exit 1
     45   ;;
     46 esac
     47 
     48 case "${1}" in
     49   "")
     50 # Make like inetd, and run the next relayer process NOW.  All the redirection
     51 # is necessary so this shell has NO remaining channel open to the net.
     52 # This will hang around for 10 minutes, and exit if no new connections arrive.
     53 # Using -n for speed, avoiding any DNS/port lookups.
     54     nc -w 600 -n -l -p $PORT -e "$0" $XNC "$CLIENT" < /dev/null > /dev/null \
     55 	2> $CFILE &
     56   ;;
     57 esac
     58 
     59 # no client yet and had an arg, this checking can be much slower now
     60 umask 077
     61 
     62 if test "$1" ; then
     63 # if magic arg, just clean up and then hit our own port to cause server exit
     64   if test "$1" = "reset" ; then
     65     rm -f $LFILE
     66     test -f "$CFILE" && rm -f $CFILE
     67     nc -w 1 -n 127.0.0.1 $PORT < /dev/null > /dev/null 2>&1
     68     exit 0
     69   fi
     70 # find our ass with both hands
     71   test ! -f "$0" && echo "Oops, cannot find my own corporeal being" && exit 1
     72 # correct launch: set up client access control, passed along thru environment.
     73   CLIENT="$1"
     74   export CLIENT
     75   test "$CFILE" || CFILE=/dev/null
     76   export CFILE
     77   touch "$CFILE"
     78 # tell us what happened during the last run, if possible
     79   if test -f "$CFILE"  ; then
     80     echo "Last connection results:"
     81     cat $CFILE
     82   fi
     83 
     84 # ping client machine and get its bare IP address
     85   CLIENT=`nc -z -v -w 8 "$1" 22000 2>&1 | sed 's/.*\[\(..*\)\].*/\1/'`
     86   test ! "$CLIENT" && echo "Can't find address of $1" && exit 1
     87 
     88 # if this was an initial launch, be informative about it
     89   echo "=== Launch: $CLIENT" >> $LFILE
     90   echo "Proxy running -- will accept connections on $PORT from $CLIENT"
     91   echo "  Logging queries to $LFILE"
     92   test -f "$CFILE" && echo "  and connection fuckups to $CFILE"
     93 
     94 # and run the first listener, showing us output just for the first hit
     95   nc -v -w 600 -n -l -p $PORT -e "$0" $XNC "$CLIENT" &
     96   exit 0
     97 fi
     98 
     99 # Fall here to handle a page.
    100 # GET type://host.name:80/file/path HTTP/1.0
    101 # Additional: trash
    102 # More: trash
    103 # <newline>
    104 
    105 read x1 x2 x3 x4
    106 echo "=== query: $x1 $x2 $x3 $x4" >> $LFILE
    107 test "$x4" && echo "extra junk after request: $x4" && exit 0
    108 # nuke questionable characters and split up the request
    109 hurl=`echo "$x2" | sed -e "s+.*//++" -e 's+[\`'\''|$;<>{}\\!*()"]++g'`
    110 # echo massaged hurl: $hurl >> $LFILE
    111 hh=`echo "$hurl" | sed -e "s+/.*++" -e "s+:.*++"`
    112 hp=`echo "$hurl" | sed -e "s+.*:++" -e "s+/.*++"`
    113 test "$hp" = "$hh" && hp=80
    114 hf=`echo "$hurl" | sed -e "s+[^/]*++"`
    115 # echo total split: $hh : $hp : $hf >> $LFILE
    116 # suck in and log the entire request, because we're curious
    117 # Fails on multipart stuff like forms; oh well...
    118 if test "$x3" ; then
    119   while read xx ; do
    120     echo "${xx}" >> $LFILE
    121     test "${xx}" || break
    122 # eew, buried returns, gross but necessary for DOS stupidity:
    123     test "${xx}" = "
    124 " && break
    125   done
    126 fi
    127 # check for non-GET *after* we log the query...
    128 test "$x1" != "GET" && echo "sorry, this proxy only does GETs" && exit 0
    129 # no, you can *not* phone home, you miserable piece of shit
    130 test "`echo $hh | fgrep -i netscap`" && \
    131   echo "access to Netscam's servers <b>DENIED.</b>" && exit 0
    132 # Do it.  30 sec net-wait time oughta be *plenty*...
    133 # Some braindead servers have forgotten how to handle the simple-query syntax.
    134 # If necessary, replace below with (echo "$x1 $hf" ; echo '') | nc...
    135 echo "$x1 $hf" | nc -w 30 "$hh" "$hp" 2> /dev/null || \
    136   echo "oops, can't get to $hh : $hp".
    137 echo "sent \"$x1 $hf\" to $hh : $hp" >> $LFILE
    138 exit 0
    139 
    140