In this lab you'll write a TCP Proxy using the same C++ asynchronous library as in the first lab. You'll learn how to write both client and server code in this lab.
A TCP proxy server is a server which acts as an intermediary between a client and another server, called the destination server. Clients establish connections to the TCP proxy server, which then establishes a connection to the destination server. The proxy server sends data received from the client to the destination server and forwards data received from the destination server to the client. Interestingly, the TCP proxy server is actually both a server and a client. It is a server to its client and a client to its destination server.
A TCP proxy server can be useful to get around services which restrict connections based on the network addresses. For example, the web page http://www.scs.cs.nyu.edu/V22.0480-003/restricted/ is only accessible from the V22.0480-003 test machines. If you try to access it from elsewhere, you will receive an access denied error. However, you can view this page from a web browser anywhere on the Internet by running a proxy server on one of the class machines. The web server will think it is serving the data to a web client on the machine running the proxy. However, the proxy is forwarding the data out of the class network, thus subverting the protection mechanism. (Note that while you can do this for the www.scs.cs.nyu server, you should not point a proxy at other restricted servers at NYU--this would violate NYU's network policy.)
The proxy server you will build for this lab will be invoked at the command line as follows:
% ./tcpproxy destination-host destination-port listen-port
For example, to redirect all connections to port 3000 on your local machine to yahoo's web server, run:
% ./tcpproxy www.yahoo.com 80 3000 &
As another example, to view the restricted web page mentioned above, you might run the following command on machine class5:
% ./tcpproxy www.scs.cs.nyu.edu 80 4000 &Then you can view the restricted web page by typing the URL http://class5.scs.cs.nyu.edu:4000/V22.0480-003/restricted/ into your browser window. The trailing slash on .../restricted/ is actually important important in this context, to avoid getting redirected to www.scs.cs.nyu.edu. Of course if someone is already using port 4000, you will need to choose another port.
The proxy server will accept connections from multiple clients and forward them using multiple connections to the server. No client or server should be able to hang the proxy server by refusing to read or write data on its connection. For instance, if one client suddenly stops reading from the socket to the proxy, other clients should not notice interruptions of service through the proxy. You will need asynchronous behavior, described in "Using TCP Through Sockets".
The proxy must also handle hung clients and servers. In particular, if one end keeps transmitting data but the the other stops reading, the proxy must not buffer an unlimited amount of data. Once the amount of buffered data in a given direction reaches some high water mark (e.g., 8K), the proxy must stop reading in that direction until the buffer drains. If the proxy has buffered data in one direction and is unable to write any of it for 10 seconds, it should abort both connection pairs.
The proxy must handle end-of-file conditions as transparently as possible. If it reads end-of-file from one socket, it should pass the condition along to the other socket (using shutdown) after writing any remaining buffered data. However, the proxy should continue to forward data in the other direction. The proxy should terminate a connection pair and close the file descriptors under either of the following two circumstances:
multifinger
directory from the first lab as a
template. First, clean the multifinger directory with the command
gmake maintainer-clean, then copy it as follows:
% cd multifinger % gmake maintainer-clean test -z "aclocal.m4 install-sh mkinstalldirs missing configure ... rm -f config.h ... This command is intended for maintainers to use; it deletes files that may require special tools to rebuild. rm -f config.status % cd .. % cp -pr multifinger tcpproxy % cd tcpproxy % rm multifinger.C multifinger.hNow you must edit the autoconf and automake configuration files. First, edit
configure.in
. At the top, you fill find the
line:
AM_INIT_AUTOMAKE(multifinger, 0.0)Change
multifinger
to tcpproxy
. (This
changes the name of the software package when you make a
distribution.)
Next, you must edit Makefile.am
to change the program you
are going to build and the source files to include. There are three
lines of interest:
bin_PROGRAMS = multifinger noinst_HEADERS = multifinger.h multifinger_SOURCES = multifinger.C
bin_PROGRAMS
simply lists all the programs contained
in the software packate. In this case, you can simply change
multifinger
to tcpproxy
, but if you wanted
to build other programs, you could include multiple entries on the
line.
noinst_HEADERS
Specifies all the header
``.h
'' files used in your software. If you forget to
specify a header file, your program will still compile, but you will
be uname to make a software distribution. The command gmake
distcheck
will fail. In this case, you might leave
noinst_HEADERS empty if you don't initially need any header files.
multifinger_SOURCES
specifies all the source files
for the multifinger program--but you aren't building multifinger (it's
no longer specified on your bin_PROGRAMS
line). Instead,
you should add a tcpproxy_SOURCES
line.
Makefile.am
might contain the
following lines:
bin_PROGRAMS = tcpproxy noinst_HEADERS = tcpproxy_SOURCES = tcpproxy.CAnd you would put the source to your TCP proxy in tcpproxy.C. Finally, when you are ready to compile, you can proceed as you did with multifinger:
% ./setup + chmod +x setup + aclocal ... + set +x % setenv DEBUG -g % ./configure --with-sfs=/usr/local/fs/debug creating cache ./config.cache checking for a BSD compatible install... /usr/bin/install -c checking whether build environment is sane... yes ... creating Makefile creating config.h % gmake ...
First, run the proxy and point it at www.scs.cs.nyu.edu's HTTP port:
% ./tcpproxy www.scs.cs.nyu.edu 80 1234Now, in another window, use telnet to fetch /cgi-bin/big through the proxy:
% telnet 127.0.0.1 1234 Trying 127.0.0.1... Connected to localhost (127.0.0.1). Escape character is '^]'. GET /cgi-bin/bigWatch the data go by for a while, then interrupt the output by typing control-], after which telnet should stop and print telnet>. Now check that the proxy hasn't been hung because telnet isn't reading data; suspend your telnet by typing ``
z
RETURN'' and fetch something else:
telnet> z Suspended % telnet 127.0.0.1 1234 Trying 127.0.0.1... Connected to localhost (127.0.0.1). Escape character is '^]'. GET /ok You were able to fetch the data. Connection closed by foreign host. % kill %telnet % [1] Terminated telnet 127.0.0.1 1234 %If you see "You were able to fetch the data," your program passes the test. Now try to access the restricted page from your web browser with a URL like http://class5.scs.cs.nyu.edu:1234/V22.0480-003/restricted/.
Once your proxy passes some basic tests, you can test it with the automated program test-tcpproxy. You can find this program on the class machines in ~class/bin/test-tcpproxy, which should be in your path by default. Assuming your proxy is in ./tcpproxy, you can test it as follows:
% test-tcpproxy ./tcpproxy Single echo connection: passed Two echo connections: passed 20 echo connections: passed Bulk data, 20 connections: passed Mix of blocked and normal: passed One-way shutdown: passed Early close: passed Non-timeout of active client: passed Timeout of lazy client: passed %Your program should pass all phases of the tests.
% gmake distcheck rm -rf tcpproxy-0.0 mkdir tcpproxy-0.0 chmod 777 tcpproxy-0.0 ... ================================================ tcpproxy-0.0.tar.gz is ready for distribution ================================================ %Also as in the previous lab, use the
script
command to
create a typescript
file.
To turn in your distribution, copy the files
tcpproxy-0.0.tar.gz
and typescript
files to
the directory ~class/handin/lab2/username
where
username is your username:
% cp tcpproxy-0.0.tar.gz ~class/handin/lab2/`logname`/ %If you have any problems about submission, please contact dm@cs.nyu.edu. The lab is due before class on Thursday, September 20th.