CSc 423 Assignment 3

Let Me Get That For You

Assigned
Due

Mar 24
90 pts
Apr 9

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:

  1. Client C wants to connect to server S at port s, but cannot do so directly.
  2. C contacts the Socks proxy server P at some known port p.
  3. C first sends P a request to connect on its behalf to S at s. The Socks server attempts this, and reports back success or failure.
  4. If P succeeded, it then uses that same connection from C and the new connection to S to forward all data back and forth in each direction.
  5. When P's forwarding loop receives end-of-transmission (recv returns zero) on one side, it “forwards” this to the other by shutting down sending on that connection. This causes the the recv on the far end (whichever direction) to return zero.
  6. When P has gotten EOT from both sides, forwarding ends.

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.

How To Run Minisocks

On Your Desktop

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.

[bennet@m-mcc-csc-01456 socks]$ ./minisocks 7768 Accepted connection from 127.0.0.1:60722 Request to proxy IP4 address 108.177.122.103 Request port number: 443 Connected to 108.177.122.103:443 from 10.27.2.212:39722 Accepted connection from 127.0.0.1:60726 Request to proxy IP4 address 74.125.138.154 Request port number: 443 Connected to 74.125.138.154:443 from 10.27.2.212:43852 Accepted connection from 127.0.0.1:60730 Request to proxy IP4 address 108.177.122.139 Request port number: 443 Connected to 108.177.122.139:443 from 10.27.2.212:35704 Accepted connection from 127.0.0.1:60734 Request to proxy IP4 address 74.125.21.132 Request port number: 443 Connected to 74.125.21.132:443 from 10.27.2.212:53218 Accepted connection from 127.0.0.1:60738 Request to proxy IP4 address 64.233.177.94 Request port number: 443 Connected to 64.233.177.94:443 from 10.27.2.212:53514 Accepted connection from 127.0.0.1:60742 Request to proxy IP4 address 108.177.122.94 Request port number: 443 Accepted connection from 127.0.0.1:60746 Request to proxy IP4 address 108.177.122.94 Request port number: 443 Connected to 108.177.122.94:443 from 10.27.2.212:49318 Connected to 108.177.122.94:443 from 10.27.2.212:49322 ^C [bennet@m-mcc-csc-01456 socks]$

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.

On Sandbox

If you are using cleansocks on Sandbox or otherwise without a GUI, you can run minisocks using a program called curl, which performs HTTP downloads and supports the Socks protocol. For a normal download (no minisocks), you might see:
[bennet@sandbox tmp]$ curl -o google.html http://www.google.com % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 13592 0 13592 0 0 126k 0 --:--:-- --:--:-- --:--:-- 126k [bennet@sandbox tmp]$ ls -l google.html -rw-rw-r-- 1 bennet bennet 13592 Feb 19 17:14 google.html [bennet@sandbox tmp]$
This asks curl to download the Google home page. You can fetch any URL with it, and you can see that it stored the result in the requested file.
To run minisocks, first download it and compile it. This will work:
[bennet@sandbox tmp]$ wget http://sandbox.mc.edu/~bennet/cs423v2/asst/minisocks.cpp --2021-02-19 17:51:14-- http://sandbox.mc.edu/~bennet/cs423v2/asst/minisocks.cpp Resolving sandbox.mc.edu (sandbox.mc.edu)... 10.27.0.23 Connecting to sandbox.mc.edu (sandbox.mc.edu)|10.27.0.23|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 8024 (7.8K) [text/plain] Saving to: ‘minisocks.cpp’ minisocks.cpp 100%[===================>] 7.84K --.-KB/s in 0s 2021-02-19 17:51:14 (525 MB/s) - ‘minisocks.cpp’ saved [8024/8024] [bennet@sandbox tmp]$ g++ -o minisocks minisocks.cpp -lcleansocks -lpthread [bennet@sandbox tmp]$
The -lpthread is the system library for threading support.
To use curl with minisocks, log into Sandbox twice, so you have two command shells in different windows. (Alternatively, putty has a tab system to the same purpose.) Then, in one window run ./minisocks 4488 (or some other port of your choice). In the other:
[bennet@sandbox tmp]$ curl --proxy socks5://localhost:4488 -o google.html http://www.google.com % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 13633 0 13633 0 0 72903 0 --:--:-- --:--:-- --:--:-- 73295 [bennet@sandbox tmp]$ ls -l google.html -rw-rw-r-- 1 bennet bennet 13633 Feb 19 17:10 google.html [bennet@sandbox tmp]$
This call to curl directs it to use a socks 5 proxy at a particular location. Make sure you specify localhost and whatever port you gave to minisocks. Curl will log as shown above, while minisock logs in the other window, like this:
./minisocks 4488 Accepted connection from 127.0.0.1:35400 Request to proxy IP4 address 108.177.122.104 Request port number: 80 Connected to 108.177.122.104:80 from 10.27.0.23:42296

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.

To get a more complex log from minisocks, you might run something like:
curl --proxy socks5://localhost:4488 -o 'file#1.html' 'http://sandbox.mc.edu/~bennet/{cs404b,cs423v2,cs314,cs485}/' \ -o goog.html https://www.google.com/-o amz.html https://www.amazon.com -Z
This does six downloads in parallel, each to its own file. You can send most any list of URLs that you like.

And while your minisocks is running, you can try this one:
[bennet@sandbox ~]$ connect-proxy -S localhost:4488 -R local sandbox.mc.edu 17 MSDOS didn't get as bad as it is overnight -- it took over ten years of careful development. -- dmeggins@aix1.uottawa.ca [bennet@sandbox ~]$
The connect-proxy command is a socks client. It will do many things, but here we are using it as a qotd client via the minisocks server.

The Assignment

You are to add two additional features to minisocks:
  • Add support for the proxy to perform address DNS lookups. That's address type 3 in the SOCKS request as described in RFC 1928. Firefox and curl use type 1, where the client sends the IP address for minisocks to connect to. For type 3, the client sends a host name, and the proxy does the translation. This is described in Sections 4 and 5 of RFC 1928.
  • Optionally require username/password authentication. This is authentication method 2 mentioned in RFC 1928 Section 3, and described in RFC 1929. After the initial request, and the server's acceptance of the method, the client sends the an account and password in plain text, which the server accepts or rejects. Your program shoud require username/password by default, and the client will be rejected if it's not offered. However, this behavior can be changed back to the original, offering only anonymous clients, by giving a negative port number. (Of course, you will need to negate the port number before trying to listen on it.) The sign on the number is just being used as a flag to the program.

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.)

Testing

On Desktop

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.

On Command Line

From the command line, curl will send the credentials if you add them the proxy URL on the command line, like:
curl --proxy socks5://username:password@localhost:4488 -o google.html http://www.google.com
The curl program sends numerical addresses, rather than symbolic ones. To test the lookup, you can use the connect-proxy program mentioned earlier. Just change the option -R local to -R remote.
[bennet@sandbox ~]$ connect-proxy -S localhost:4488 -R remote sandbox.mc.edu 17 A watched clock never boils. [bennet@sandbox ~]$
Connect_proxy will also attempt password authentication, if you call it so:
[bennet@sandbox ~]$ connect-proxy -S fred@localhost:4488 -R remote sandbox.mc.edu 17 Enter SOCKS5 password for fred@localhost: Howe's Law: Everyone has a scheme that will not work. [bennet@sandbox ~]$
Notice the line that asks for a password, which is not displayed while being typed.

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

tshark -i lo -T fields -e tcp -e data port 4488
(substituting your port number) to see what's happening.

Notes On The Minisocks Source

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.