This assignment involves implementing parts of the Socks protocol, RFC 1928. This is a proxy protocol designed to allow computers inside a firewall to access resources outside, which they cannot access directly. The procedure is something like this:
You are given minisocks, a simple cleansocks-based program which implements a minimal Socks service, following RFC 1928. (It's not technically in compliance since it doesn't implement GSSAPI-based authentication, but it works fine with clients that don't require that, or anything else it doesn't do.)
Minisocks listens for connections on localhost, and accepts Socks requests to proxy TCP connections anywhere else.
The most interesting way to run minisocks is to compile it on your computer, and let it proxy for Firefox. If you don't normally use Fox, go ahead and install it to run the tests; you don't have to convert.
First, compile minisocks and run it. Give a port number on the command line, or it will ask for one. (The standard port is 1080.) Leave it running in its window.
In Firefox, open the preferences window. Use the menus,
or just visit about:preferences (just type that into the
location stripe). Scroll to the bottom and find the
section “Network Settings”, and a button to open them.
(You might want to note the initial selection, probably “None”, or
“use system proxy setting,” to make sure you can put it back.)
Select manual proxy. Type localhost as the
SOCKS host, enter the port you told minisocks to use, select Version 5,
and also use for HTTPS. Then, if your screen is small, scroll down, and
make sure to uncheck “Proxy DNS when using SOCKS v5”.
Then say OK. Now, when you
visit a web page, Firefox will connect through minisocks, which should
print messages showing what it is doing. Minisocks is forwarding
all the traffic between the browser and the servers you are visiting.
Notice that minisocks was stopped by pressing control-C. It actually has no stop command, so we are using the OS to kill it. This is actually common enough for a simple server, though serious ones often have some way for a client to connect and request that it terminate.
If you're working on Sandbox, you might want to plan to use some different port than 4488. Port numbers are shared across the system, so if several people start using the same ones at once, they'll start getting address-in-use errors, or be using each others proxy servers, perhaps without noticing.
When a username and password are sent, you should log the username and whether the password was accepted. When a host name is sent to be looked up, log that as well.
Normally, such a proxy would read passwords from disk or some other source. For this exercise, simply code a list of valid username/password pairs in your program. Code at least three, one of which should be the userid fred with the password password. (Fred never was very security-conscious.)
For testing with Firefox, you will need to install a Firefox
extension known as FoxyProxy.
Unfortunately,
standard Firefox does not have a provision for sending the credentials
to a server, but FoxyProxy does. FoxyProxy also sends hostnames
for the proxy to look up, so it will test that feature. When
installed, clicking the icon will bring up a small box like the one on the
right. This example shows two proxy definitions which I have created, which
a new install won't have.
Start by clicking on the Options button. This will create a new window showing your definitions (if any) like the one below left. Use the add button on the left to create a new one. You'll get a screen something like the one below right. Choose SOCKS5 type, address localhost, and your favorite port number. If you fill in the username and password, Foxy will authenticate to the socks server. If you don't, it won't. Give your setting set a name, and save.
After you make settings, their names will appear in the small menu that comes up from the FoxyProxy icon, as shown above. Use that to click on a name to activate a particular config, or to deactivate Foxy and return to Firefox proxy settings.
You can create settings to test aspects of your modified minisocks. Use some settings with a username and password to test that feature. Foxyproxy will ask minisocks to look up host names, so when it is on that feature is in use. Turn it off and use the basic Firefox proxy to test with IP addresses.
In fact, connect_proxy always offers both user/pass and anonymous authentication to the socks server. If you don't give it a user name, it will use your Sandbox login id.
On the off chance that your program does not work the first time, logging is quite helpful for debugging. You also might use Wireshark to examine the traffic to your server. Tell it to examine the loop-back device, and you probably won't see much or any extraneous traffic. On Sandbox, you can do the same sort of thing with tshark, though it's a bit clunky. Before running a test, try creating a third Sandbox window and running
The main program follows a standard server pattern. It creates a socket, binds it to an endpoint, then puts it into listening mode. It then loops calling accept to process individual clients. Accept is a blocking call which returns each time a client connects. Unlike most servers, this binds to a port on the loop-back address, 127.0.0.1, so it cannot accept connections from outside. Most servers bind to the wild card address any, or the address of a specific external interface.
Each iteration of the main loop that accepts a client starts a thread to process it (line 293), and detaches it to run on its own. This simple approach is liable to flooding by a large number of clients. A more complete service would manage this more carefully.
The thread runs the function server_catcher, which just wraps serve_client. That function starts at line 122. You can see it step through the operations described in RFC 1928. It reads the initial message from the client (Section 3), and examines the list of offered authentication methods in the request to make sure the no-authentication method is offered. The server then either sends a negative response and closes, or responds accepting the no-authentication.
This is where you will add code to receive and check the username/password, if that method was selected.
Then (line 145), it reads the request (per Section 4) and examines the requested address type. Note that it branches based on that type because different reading code is needed for the different addresses. If it finds an address it likes, it tries to connect to it (line 216), then replies to the client in accordance with Section 6. If there was anything the server didn't like, or the connection failed, it responds negatively (line 228 and following) and closes. On success, it responds appropriately, giving information about the connection it made (line 235 ff). Notice that the response always contains connection information, which the error response must fill with zeros.
After sending this response, the server copies data each way. It does this using a function fwd, which copies data from one port to another. At line 246, this function is started twice, once for each direction, in different threads. The function itself starts at line 99.
Also note the function readvar which is used to read variable-length fields. The only one it reads right now is the list of authentication methods, but you will find it useful to read host names and credentials.
Submission
When your program is working, nicely commented and properly indented, submit it using the form here.