ࡱ> '` )Nbjbj{P{P 4v::)FP"P"P"P"D"Tm`j"v#v#v#v#Q$Q$Q$_______$ah?dj`Q$Q$Q$Q$Q$`v#v#'`O-O-O-Q$v#v#_O-Q$_O-O-Zlr^v#" 6P"*\*_$=`0m`,\Fd,dTr^r^Jd^ Q$Q$O-Q$Q$Q$Q$Q$``9-Q$Q$Q$m`Q$Q$Q$Q$$, $,  Modifying Tinyproxy to Cache User Requests Joe Larsen Abstract In order to provide internet connectivity to users in areas of the world were power is a limited resource solutions must be implemented that allows for a user request to be cached while networking equipment is turned on. To achieve this while appearing to have an always on internet connection this document will describe how Tinyproxy can be modified user Python 2.5 to check for a connection before it allows internet requests to be sent to a web server. Keywords Tinyproxy, proxy server, Python, Ubuntu, Linux, HTTP, vim, lynx, Internet-on-demand, always on internet Introduction Today there is a large focus on energy efficiency to reduce ones carbon footprint or as a result of limited resources. In the developed world, most people enjoy always on internet connectivity and while seen as a convenience this is an inefficient use of resources. This is especially true when someones network is comprised of computers that act as clients and not servers. As a result a solution is sought in which networking equipment can be turned off when not in use but still provide the same seamless user experience that one would expect with a always on connection. Objective In order to achieve the desired user experience their must be software that operates in the background which will: Detect the presence of an internet connection Catch outgoing user requests until the internet connection is detected Include an interface to turn on networking devices There are a number of ways that one can achieve these goals. Because this particular application is part of an existing project that runs off of Linux the solution that has been chosen is to modify an application currently being used called Tinyproxy. Tinyproxy is a proxy server. A proxy server can be used to create a local cache of web sites, to implement a content filter, or to provide a layer of anonymity to someones internet browsing activity. All of these activities involve Tinyproxy being used as an intermediary between the user and the web server in all outbound connections. In being an intermediary Tinyproxy is processing the data of the user request before sending it out. In effect this is caching the user requests before they are sent out. In order to cache the user requests until the internet connection is detected, either a function that involves processing the request or sending a request out to a network interface will have to modify. This application note will describe how to achieve this by modifying the function used to send requests onto a network interface. While Tinyproxy is written in C, this application note will describe how to do this with Python 2.5. This is done for no other reason than the author of this note is most familiar with python. The logic used should be easily ported to C by someone familiar with the language. Implementation This section will provide a step by step description of how to achieve the objectives outlined above. First the code for Tinyproxy must be analyzed to determine functionality that requires modification. Then the modifications have to be made. Finally the system has to be tested. In order to achieve the desired functionality the function handling all outgoing network communications will be edited. This function is called handle_connection() and is located in the file {tinyproxy_root}/src/reqs.c. This function was chosen because request can be cached immediately before being sent to a network interface. As a result any processing such as blacklist content filtering can be preformed first. Modifying TinyProxy The first thing that needs to be done is acquiring the source code of Tinyproxy. Then uncompress the file that was received. To do this open terminal and type: wget https://www.banu.com/pub/tinyproxy/1.8/tinyproxy-1.8.1.tar.bz2 tar xsvf ./tinyproxy-1.8.1.tar.bz2 This application note will use vim to edit all C files. Open the file tinyproxy-1.8.1/scr/reqs.c. Find the function handle_connections(). An easy way to do this would be to type: :/handle_connection Once the handle_connections() function is found, a system call needs be added to run an external script. As was alluded to in the introduction Python will be used to achieve the objectives. In order to do this the function system() will be used. This allows a command to be passed to terminal while an application is running. In this case the location of the executable python script that will be created is passed to terminal. This will effectively run that script while suspending the other processes of Tinyproxy (not allowing the request to be sent out over a network). In order to use the system() function you have to place the following code in the handle_connection() function: int res; log_message (LOG_CONN, "Beginning IP test"); res = system ("/home/ece480/test/test.py"); if (res == -1) log_message (LOG_CONN, "Error Running Python Script"); else log_message (LOG_CONN, "Connection Confirmed"); This would be placed below the block of code where already existing variable declarations for the function exist. Line 1 is simply declaring a variable that will be used to determine if the system() function was run successfully. Lines 3, 8, and 11 are log entries that will be written to the tinyproxy.log file. Line 5 is where the system() function is used. The input to the function is a terminal command; in this case it is the location of an executable file. If the command ran successfully, the system() function will return a positive number or 0. If it fails it will return a negative number. Creating a python script When creating a Python application it is best to use an IDE that is either built for or has plug-ins for Python, due to the importance of white space and tabs. Two suggestions would be IDLE, the GUI command shell that comes with Python or NetBeans from Oracle with the Python 2.5 plug-in. The fist thing that must be done is declaring the application this script is to be run with (#! /usr/bin/python) and import any libraries that we will be using. The command library is used to make calls to terminal and return the output from terminal to Python. The sys library is used to determine the condition under which the python script is exiting and redirect stdout to a file for log entries. The exit condition is the value passed to the res variable on line 5 in the Tinyproxy modification code block. The time library will be used to generate time stamps for the log entries. This can be done with the following code: #! /usr/bin/python import commands import sys import time saveout=sys.stdout fsock=open("/usr/local/var/log/python.log","a") Lines 6 and 7 are used to direct print statements to stdout and open a log file where information will be appended to. Any strings handled by the print function will be written to that log file. The remainder of this script will be broken up into a series of functions called getIP(), sendSig(), exiting(), and main(). The names of these functions should be self explanatory, but they will be covered in detail. The first function getIP() makes a system call using the command ifconfig to get the computers IP address. The information is then piped into grep, cut, and awk to return a usable string. The function then checks the length of the string, if there is no IP address, the value of the IP Address is set to none. This is done for logging purposes. Finally the function returns the IP address. def getIP(): ip=commands.getoutput("ifconfig eth0 |grep 'inet addr'|cut -d':' -f2|awk '{print $1}'") if len(ip)==0: ip="none" return ip Next a function has to be written to send a turn on signal. This function will take care of turning on the networking equipment. This functionality is outside the scope of this application note, but it is still important to log. As of March 31, 2010 the sendSig() function looks like: def sendSig(): print "%s STATUS Sending turn on single" \ % time.strftime("%Y-%m-%d %H:%M:%S") # TODO - Write code for this function The next function handles how the python script terminates. This function handles logging the close of the script, stdout control being returned to the system, closing the log file, and sending an exit code to the res variable in the code that was added to Tinyproxy. def exiting(): print "%s CLOSING" % time.strftime("%Y-%m-%d %H:%M:%S") sys.stdout=saveout fsock.close sys.exit(0) The final function is the main function. This starts an infinite while loop. After making a call to the getIP() the script checks the IP Address against a value defined in the application. In this particular instance it is 35.9.132.239. If the actual IP address and the value supplied are the same the script will break send a turn on signal, log the event, and continue the proxy server functionality in Tinyproxy. The reason for sending a turn on signal is to ensure the networking equipment stays on, as other components on in this project run off of a timer and that turn on signal will reset the timer. All of the IP Addresses in this implementation are assigned as static IP addresses. This application is assuming that if an IP address is assigned by a router that router is connected to the internet. If this were to be implemented on a DHCP network regular expressions could be used to ensure the IP address falls within an excepted range. def main(): sys.stdout=fsock ip=getIP() print "%s STARTING Entering main loop. IP Address is: %s" \ % (time.strftime("%Y-%m-%d %H:%M:%S"), ip) count=0 while True: n=getIP() if n=="35.9.132.239": print "%s STATUS IP Address Confirmed" \ % time.strftime("%Y-%m-%d %H:%M:%S") sendSig() exiting() break If the condition on line 9 is not met, then the application runs the sendSig() function ever 100 cycles through the while loop. This information is then logged. The code used to implement this is: else: sendSig() counter=count%100 trueCount=count/100 if counter==0: print "%s STATUS IP Address invalid: %s" \ % (time.strftime("%Y-%m-%d %H:%M:%S"), n) print "%s STATUS IP Address has been checked %d" \ % (time.strftime("%Y-%m-%d %H:%M:%S"), trueCount) count=count+1 Finally you will want to include a main()function at the end of the script. Then save the script in the same location defined by line 5 in the C code used to modify Tinyproxy. Once this has been completed you will need to provide permissions for the script to be executed. The easiest way to do this is by typing the following command into terminal: chmod a+x /home/ece480/test/test.py Compiling Tinyproxy Compiling Tinyproxy is incredibly easy. Before compiling if an already existing binary is installed, it needs to be removed by issuing the command: sudo apt-get remove tinyproxy After doing this docbook-xsl needs to be installed sudo apt-get install docbook-xsl At this point issue the following commands: cd ~/tinyproxy-1.8.1 ./configure make make install After running each command, ensure that there are no errors. If you have encountered errors ensure that they are corrected, and reissue the command before moving on. Otherwise the Tinyproxy will not install properly. Two errors that I encountered when attempting to run Tinyproxy were: The log file in /usr/local/var/log/tinyproxy.log could not be found or created Tinyproxy could not write the PID to the file /user/local/var/run/tinyproxy.pid These two problems are very easy to fix, simply issue the following commands: sudo touch /usr/local/log/tinyproxy.log sudo touch /usr/local/run/tinyproxy.pid sudo chmod 666 /usr/local/log/tinyproxy.log sudo chmod 666 /usr/local/run/tinyproxy.log The above commands are creating the files, if they do not already exist, and then changing the permissions associated with the file so information can be written to them. Once this is complete the application can be tested. Testing - Setting up Lynx To test Tinyproxy an HTTP browser is needed. This section will explain how to configure a web browser to pass all requests though a proxy server. This document will be using lynx, a terminal based web browser. First one needs to ensure that lynx is on their system. This can be done by typing the command: sudo apt-get install lynx Once lynx is installed the configuration file needs to be edited to forward all requests to a proxy server. Because tiny proxy is operating on the same computer that lynx will be running on the domain will be localhost and the forward port will be 8888. To edit the lynx configuration file type: sudo vim /etc/lynx.cfg Inside of vim type :/http_proxy: This will search for the string http_proxy:. A section of the configuration file will be presented, and should appear similar to: #http_proxy:http://some.server.dom:port/ #https_proxy:http://some.server.dom:port/ #ftp_proxy:http://some.server.dom:port/ #gopher_proxy:http://some.server.dom:port/ #news_proxy:http://some.server.dom:port/ #newspost_proxy:http://some.server.dom:port/ #newsreply_proxy:http://some.server.dom:port/ #snews_proxy:http://some.server.dom:port/ #snewspost_proxy:http://some.server.do]:port/ #snewsreply_proxy:http://some.server.dom:port/ #nntp_proxy:http://some.server.dom:port/ #wais_proxy:http://some.server.dom:port/ #finger_proxy:http://some.server.dom:port/ #cso_proxy:http://some.server.dom:port/ #no_proxy:host.domain.dom Edit the first line of this section to read: http_proxy:http://localhost:8888/ Testing Tinyproxy Once this is completed the application can be tested to ensure that it meets the objectives. In order to do this open two additional terminal windows and run the following commands: tail f /usr/local/log/tinyproxy.log tail f /usr/local/log/python.log These two commands will dynamically output the log files into terminal, so that Tinyproxys activity can be followed in real time. In a third terminal window type: lynx www.msu.edu The web page should load, additionally the log files should look like: CONNECT Mar 31 22:54:14 [13853]: Beginning IP test CONNECT Mar 31 22:54:14 [13853]: Connection Confirmed CONNECT Mar 31 22:54:14 [13853]: Connect (file descriptor 6): localhost [127.0.0.1] CONNECT Mar 31 22:54:14 [13853]: Request (file descriptor 6): GET http://www.msu.edu/ HTTP/1.0 INFO Mar 31 22:54:14 [13853]: No proxy for www.msu.edu CONNECT Mar 31 22:54:14 [13853]: Established connection to host "www.msu.edu" using file descriptor 7. INFO Mar 31 22:54:14 [13853]: Closed connection between local client (fd:6) and remote client (fd:7) NOTICE Mar 31 22:54:14 [13853]: Waiting servers (1766203423) exceeds MaxSpareServers (20). Killing child. Looking at lines 5 and 6 provides evidence that Tinyproxy did break to run the python script. In order to ensure the script actually ran as expected the python.log file needs to be examined: 2010-03-31 23:07:33 STARTING Entering main loop. IP Address is: 35.9.132.239 2010-03-31 23:07:33 STATUS IP Address Confirmed 2010-03-31 23:07:33 STATUS Sending turn on single 2010-03-31 23:07:33 CLOSING This is how a log should look if there was an active internet connection. If the internet connection was to be disconnected by unplugging the Ethernet cable and a request was made to a website the log file would look similar to this: 2010-03-31 23:07:33 STARTING Entering main loop. IP Address is: 35.9.132.239 2010-03-31 23:07:33 STATUS IP Address invalid: none 2010-03-31 23:07:33 STATUS IP Address has been checked 0 2010-03-31 23:07:33 STATUS Sending turn on single 2010-03-31 23:07:33 STATUS Sending turn on single 2010-03-31 23:07:33 STATUS Sending turn on single 2010-03-31 23:07:33 STATUS Sending turn on single 2010-03-31 23:07:33 STATUS Sending turn on single 2010-03-31 23:07:33 STATUS Sending turn on single 2010-03-31 23:07:33 STATUS IP Address Confirmed 2010-03-31 23:07:33 STATUS Sending turn on single 2010-03-31 23:07:33 CLOSING Lines 10-11 are a result of plugging the Ethernet cable back into the physical interface, allowing the computer to negotiate with a router for its IP Address. The browser should also load the webpage. Conclusion This application note describes how to modify Tinyproxy to work in an Internet-on-demand architecture to detect an internet connection, catch outgoing user requests, and create the interface to send a turn on signal. Hopefully the methodology from this application note can be used to include additional functionality into Tinyproxy or other applications. Some areas are still in need for improvement. An evaluation of the security of the overall system because in more than one instance execute, read, and write privileges was given to all users because it was easy. Also depending on the application it would be worthwhile to check internet connectivity instead of just checking for a connection on the LAN. References  HYPERLINK "https://www.banu.com/tinyproxy/" https://www.banu.com/tinyproxy/  HYPERLINK "http://en.wikipedia.org/wiki/Proxy_server" http://en.wikipedia.org/wiki/Proxy_server  HYPERLINK "http://ubuntuforums.org/showthread.php?t=1047150&page3" http://ubuntuforums.org/showthread.php?t=1047150&page3 -  HYPERLINK "http://www.linuxquestions.org/questions/programming-9/using-grep-awk-get-ip-address-627626/" http://www.linuxquestions.org/questions/programming-9/using-grep-awk-get-ip-address-627626/  HYPERLINK "http://docs.python.org/library/time.html" http://docs.python.org/library/time.html  HYPERLINK "http://diveintopython.org/scripts_and_streams/stdin_stdout_stderr.html" http://diveintopython.org/scripts_and_streams/stdin_stdout_stderr.html  HYPERLINK "http://docs.python.org/library/commands.html" http://docs.python.org/library/commands.html Tinyproxy man page 6<   s  X Y +JLMZ;s   !ÿǻˣh{fhA\hf\h:LhLih*vh hhhCUh$h=Fh%rhhyhK}*h!hph4(h!h( /0Jh!hp0J h62Ph62Ph!h62P9+6789:;<E       Y & Fdhgd'"gdjvdhgd'"gd62Pdhgd!gd62P$a$gd62P$a$gd62P)N ]l';B H & Fh^hgd'"dhgd'"  dh` gd'"  & FdhgdVgdjvdhgd'" hdh`hgd'" & Fdhgd'")*Eb&':;dmB 'zGH]e [c-5ǷǷdzdzǷǷǯǑˍhVhBr0JhBrh'" h h CJOJQJ^JaJhVh 0Jh h? hVh|r0J hA\h{fh|rhVh{f hjvhG!hG!hnm{ h{fh{fh{fOJQJ^Jh{fh{fOJQJ^J4.efk1!!!!!!!%" & F hhx^hgd'" & F hh^hgd'"gdjvdhgd'" & Fh^hgd'"5\|401< ? !!!*!6!:!!!!!%"9#@#B#K#M#V#\#b####$ $O$S$U$X$^$a$$续hv5hv50Jhv5hs7^0Jhs7^ hs7^hJCJOJQJ^JaJhJCJOJQJ^JaJ hJhJCJOJQJ^JaJhJhJ0Jhv5hJ0JhVhV0JhJhiFhVhBr0JhVhBr4%""I%Z%%%%%''G't'x''((() & F hhdd[$\$^hgd'" & F hhd[$^hgdv5 dhxgdv5 & Fh^hgd'" & F hhdd[$\$^hgd'" hdh`hgd'"$H%I%%%&&''''x({((2)))*****k++,,--z.ջբ~zzveWehoCJOJQJ^JaJ hIYhIYCJOJQJ^JaJhIYhv5h*ZOJQJ^Jh*Zh*ZOJQJ^Jhv5h*Z0Jh*Z h*Zh*ZCJOJQJ^JaJh'"hJ h*Zh kCJOJQJ^JaJhv5h k0Jh khs7^CJOJQJ^JaJ hs7^hs7^CJOJQJ^JaJhs7^hC)")2),, --]------.E.W.i.{.@/I/Z/s/ & Fhx^hgdv5 x`gdv5 & Fh^hgd'" hdh`hgd'" & F hhdd[$\$^hgd'"z.{...@/L/P/Z/a/z00000000001112232422222{334444I5j55ѲѤ}yyynjyjajajhShr0JhrhjvhCJaJh hchohSho hchchchcOJQJ^JhchIYCJOJQJ^JaJ hchcCJOJQJ^JaJhcCJOJQJ^JaJ hchIYCJOJQJ^JaJh L'hIY0JhIY hIYh*ZCJOJQJ^JaJ&s////0Y000242H222.3O3{33333gdSdhgd'"dhgd'"gdjvdhgdjv hdh`hgd'" & Fhx^hgdjv & Fh^hgd'"3445k5l555 666b6B7\78899:::;2;gdjvdhgd'"gdjv dh^` gd'"gdjv & Fdhgd'"dhgd'" dhxgdS55555 66666D6I6b6A7B7I7L789y9999999:::::*=K=L=^==>>[>>>˺ˤ˭ː{wswsoh\hGihr h'"h'"hjvh'"5OJQJ^Jhjvh'"OJQJ^J hX[#h'"hX[#h'"0J h4(h'" h'"0Jh4(h'"0Jh L'hjvh'"h'"h'"OJQJh'"OJQJhSCJaJhjvhGiCJaJhjvhrCJaJ'2;[;;;;<=<f<<<<<<*=L=^=>9>[>>?W?? & F hh^hgdjvdhgd'" dhxgdjvgdjvgdjvdhgd'"gdjv>?V?W?AABBCCFGGG:I[IgIjI~IJJJJJJJJJJJJJK/K1K2K3K\K]K^K_KkKKKɼ׸zvov h62Ph62Ph62Pjh62PUj h L'UhOkVh L'0Jjh L'U h L'h L'jh L'Uh L'h hoh L'h L'CJOJQJh L'CJOJQJhjvh6#2hBr hh h(h(h\h(hjvh\CJaJ+??@{@@ AAABC8CmCCsDDD7EmEEE & F hh^hgdjv hdhx`hgd L' & F hh^hgdjv hdhx`hgdjv & F hh^hgdjvEFEF{FFFFGG:IJJJ^KKL MMN)Ngd L'gd L'dhgd'"gdjv hdh`hgd L' & F hh^hgdjvKKKKKKKKKHLJLKLLLLLLLLLLLL M M M MM_MaMbMcMMMMMMMMMMNN(N)N߾߳ߨjh62PUjh62PUjh62PUjh62PU h62Ph62Ph L'h62PhOkVh62P0Jjh62PUjBh62PU+21h:ps7^/ =!"#$%  DyK  https://www.banu.com/tinyproxy/yK Xhttps://www.banu.com/tinyproxy/yX;H,]ą'c5DyK *http://en.wikipedia.org/wiki/Proxy_serveryK lhttp://en.wikipedia.org/wiki/Proxy_serveryX;H,]ą'ciDyK 7http://ubuntuforums.org/showthread.php?t=1047150&page3yK http://ubuntuforums.org/showthread.php?t=1047150&page3yX;H,]ą'cDyK \http://www.linuxquestions.org/questions/programming-9/using-grep-awk-get-ip-address-627626/yK http://www.linuxquestions.org/questions/programming-9/using-grep-awk-get-ip-address-627626/yX;H,]ą'c1DyK )http://docs.python.org/library/time.htmlyK jhttp://docs.python.org/library/time.htmlyX;H,]ą'cDyK Ghttp://diveintopython.org/scripts_and_streams/stdin_stdout_stderr.htmlyK http://diveintopython.org/scripts_and_streams/stdin_stdout_stderr.htmlyX;H,]ą'cADyK -http://docs.python.org/library/commands.htmlyK rhttp://docs.python.org/library/commands.htmlyX;H,]ą'c@@@ NormalCJ_HaJmH sH tH ^@^ jv Heading 1$<@&"5CJ KH OJPJQJ\^JaJ V@V 62P Heading 3$<@&5CJOJQJ\^JaJDA@D Default Paragraph FontRi@R  Table Normal4 l4a (k@(No List 6U@6 A\ Hyperlink >*B*phHOH TLX Blockquote xx^ OJQJVOV `+Blockquote Char CJOJQJ_HaJmH sH tH ,O", `+codeOJQJJO1J `+ code Char CJOJQJ_HaJmH sH tH HO!BH dW3Style code + 10 ptxCJPOQP jv Char Char1"5CJ KH OJPJQJ\^JaJ Z>@Z jvTitle$<@&a$"5CJ KHOJPJQJ\^JaJ NOqN jv Char Char"5CJ KHOJPJQJ\^JaJ )Fv+6789:;<E Y] l ';B H.efk1%IZGtx !"!2!$$ %%]%%%%%%&E&W&i&{&@'I'Z's''''(Y(((*4*H***.+O+{+++++,,-k-l--- .6.b.B/\/0011222323[33334=4f444444*5L5^5696[667W7778{88 999:;8;m;;s<<<7=m===>E>{>>>>??:ABBB^CCD EEF+F0(000000000<00000000000 0 0 000000] 0] 00' 0' 0'0'0'0'0'0' 0' 0' 0' 0' 0' 0' 0' 0' 0' 0 ' 0 '0'0'0'000 0 0 0 0 0 0 000 0 0 0 0 00 0 0 0 0 00 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0  0  0  0  0 0 0 0 0 0 0 0 0 0 0 000004*04*04*04*04*04*04*04*04*04*04* 04* 04*04*04*04*04*04*04*04*00B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/0B/00L50L50L50L50L50L5 0L5 0L5 0L5 0L5 0L5 0L5 0L5 0L50L5 0L5 0L5 0L5 0L50L5 0L5 0L5 0L5 0L5 0L5 0L5 0L5 0L5 0L5 0 L5 0 L5 0 L50000000000000 ';B?:ABBB^CCD EE+F00U000000000000U00000000000000000005$z.5>K)N(,.0257: %")s/32;?E)N)+-/134689)N*BBBB2C\C^CCCCKDDDD E EbEEEEF)FXXXXXXX8@0(  B S  ?  )AGirO X  ' F T V ` 1:#'% .9kv"Z`9>BI OS^aMR^`asu} Q^  ! !!!!!&!.!!!""$%%%%%%%j%w%%%%%"&/&M&T&&&P'W'z''''m(z(((W)`)****>*G*S*\***** ++.+2+C+N+{+}+b,k,,,,,-$-U-j-------- . .....5.6.:.;.@.F.a.d/m/00y111112)23222222330333Y3\333333344;4>4d4g44444444T5]5686B6Z6668 899':0:@ @A"AFF+F ( &z]d[b9?!!%$%&&((****.+2+{+}+++++++---- ..6.:.00111145956696=667+F33333333333333333333333333333333333"#*&-BBB]C^CCCDD E EEEF(F+F+FpD%Ȁ:}?x; fr]9 yj^_BtWI%><18=@8]VxIx2XKl1t=N@ W0|]4Dm;c&, !bzl {%T>9l9ph ^`hH.h ^`hH.h pLp^p`LhH.h @ @ ^@ `hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h PLP^P`LhH.^`.^`.pp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`.h ^`hH.h ^`hH.h pLp^p`LhH.h @ @ ^@ `hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h PLP^P`LhH.h ^`hH.h ^`hH.h pLp^p`LhH.h @ @ ^@ `hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h PLP^P`LhH.h^`OJQJo(hHhpp^p`OJQJ^Jo(hHoh@ @ ^@ `OJQJo(hHh^`OJQJo(hHh^`OJQJ^Jo(hHoh^`OJQJo(hHh^`OJQJo(hHhPP^P`OJQJ^Jo(hHoh  ^ `OJQJo(hHh 8^8`hH.h ^`hH.h  L^ `LhH.h  ^ `hH.h x^x`hH.h HL^H`LhH.h ^`hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h pLp^p`LhH.h @ @ ^@ `hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h PLP^P`LhH.h ^`hH.h ^`hH.h pL^p`LhH.h @ ^@ `hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h PL^P`LhH.h ^`hH.h ^`hH.h pLp^p`LhH.h @ @ ^@ `hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h PLP^P`LhH.h^`OJQJo(hH$h^`OJQJ^Jo(hHohpp^p`OJQJo(hHh@ @ ^@ `OJQJo(hHh^`OJQJ^Jo(hHoh^`OJQJo(hHh^`OJQJo(hHh^`OJQJ^Jo(hHohPP^P`OJQJo(hHh ^`hH.h ^`hH.h pLp^p`LhH.h @ @ ^@ `hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h PLP^P`LhH.h^`OJQJo(hHh^`OJQJ^Jo(hHohpp^p`OJQJo(hHh@ @ ^@ `OJQJo(hHh^`OJQJ^Jo(hHoh^`OJQJo(hHh^`OJQJo(hHh^`OJQJ^Jo(hHohPP^P`OJQJo(hHh^`OJQJo(hHhpp^p`OJQJ^Jo(hHoh@ @ ^@ `OJQJo(hHh^`OJQJo(hHh^`OJQJ^Jo(hHoh^`OJQJo(hHh^`OJQJo(hHhPP^P`OJQJ^Jo(hHoh  ^ `OJQJo(hH^`.^`.pp^p`.@ @ ^@ `.^`.^`.^`.^`.PP^P`.h^`OJQJo(hH$hpp^p`OJQJ^Jo(hHoh@ @ ^@ `OJQJo(hHh^`OJQJo(hHh^`OJQJ^Jo(hHoh^`OJQJo(hHh^`OJQJo(hHhPP^P`OJQJ^Jo(hHoh  ^ `OJQJo(hHh ^`hH.h ^`hH.h pLp^p`LhH.h @ @ ^@ `hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h PLP^P`LhH.h ^`hH.h ^`hH.h pLp^p`LhH.h @ @ ^@ `hH.h ^`hH.h L^`LhH.h ^`hH.h ^`hH.h PLP^P`LhH.h ^`hH.h p^p`hH.h @ L^@ `LhH.h ^`hH.h ^`hH.h L^`LhH.h ^`hH.h P^P`hH.h  L^ `LhH.t=N Wjm;c0{; 8=@]VxII%pD%9 2XKbzl<10|]^_B>9                           ?P                                   *>                                   *>                                   c/0?$rRC_?iO=<?  CU\G!'"X[# L'4(K}*`+T.( /6#2dW314v5=FiF:L62PXTTLXIYs7^GiLi%r|r*vnm{c!!V(pJ2of\Br A\{f(Cjv$rS*Z y k'*+F@L#)Fp@UnknownG: Times New Roman5Symbol3& : Arial?5 z Courier New7K@Cambria;Wingdings"qh//,x ;#x ;#!24dFF 2QHP)?p2 Introduction Joe Larsen Joe LarsenT             Oh+'0   @ L X dpxIntroduction Joe LarsenNormal Joe Larsen2Microsoft Office Word@%@4D}@%@%x ;՜.+,D՜.+,h$ hp  4Michigan State University College of Engineering#F'  Introduction Title 8@ _PID_HLINKSAl*Q^-http://docs.python.org/library/commands.htmlG EGhttp://diveintopython.org/scripts_and_streams/stdin_stdout_stderr.htmlG BL )http://docs.python.org/library/time.htmlG em \http://www.linuxquestions.org/questions/programming-9/using-grep-awk-get-ip-address-627626/G >w7http://ubuntuforums.org/showthread.php?t=1047150&page3G s*http://en.wikipedia.org/wiki/Proxy_serverG 8. https://www.banu.com/tinyproxy/G   !"#$%&'()*+,-./0123456789:;=>?@ABCEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvxyz{|}~Root Entry F6Data <1TableDdWordDocument4vSummaryInformation(wDocumentSummaryInformation8CompObjq  FMicrosoft Office Word Document MSWordDocWord.Document.89q