A generic socket proxy implemented in ASP.NET
Why on earth do something like this?
I frequently work in offices where I only have access to the internet via a HTTP proxy. E-mail protocols like SMTP, POP3 and IMAP cannot be proxied via http so I download mails via GPRS/UMTS when needed. The problem is that it costs a fortune when someone sends you a gigantic Power Point presentation by mistake.
This week it happened again, several times, and I decided to do something about it. I found HTTPort, and several similar to it, but they all require me to install a new "server" somewhere. A new service that may have security problems and that may be difficult/impossible to installl with a hosting provider.
In the end I decided to roll my own ASP.NET based solution for several reasons:
- Security/stability: Implementing a new socket server is always a risk in terms of buffer overruns etc. IIS/ASP.NET is heavilyt tested offers a lot of monitoring features as well.
- Authorization: Anything supported by IIS, anonymous, basic security, NT security, digital certificates, ...
- Encryption. Data can be encrypted using a free SSL certificate.
- Easy to deploy: Deploy the ASP.NET server at any site that support ASP.NET and sticky sessions.
- I cannot use a VPN as my cell provider blocks some of the ports used by Microsoft VPNs.
I have been busy working on it the last couple of nights and have come up with a working solution that is "good enough for me". I do not intend to spend more time working on the user interface, or adding features I do not need. Feel free to download it and extend it in any way you see fit as long as you link back to this site. Use it at your own risk! All I can say is that I have used it exclusively for my e-mail the last few days and I have successfully used Microsoft Terminal Server via a http proxy over a slooooow link.
How it works
The Socket Proxy consists of two parts: a server and a client. The client makes a http request to the server passing the server and port it would like to talk to. The server opens the connection to the remote host/port and stores the socket in the session if the client is allowed to do it. Multiple calls are made to proxy.aspx to proxy the actual payload before the client or server closes the connection. Close.aspx is use to close and clean up socket and session data.
- Socket Proxy Server -
The Socket Proxy server is implemented in ASP.NET. Thanks to the extensive .NET libraries it is -tiny-. There are 3 aspx files (open.aspx, proxy.aspx, close.aspx) and ~500 lines of C# code, comments included! A cup of coffee is enough to go through the code.
- Socket Proxy Client -
The client is bigger than the server as I got carried away and added a notification icon with statistics and some other features that are not really needed. The client can be configured to run as a normal windows form or as a notification icon only and supports a http proxy with/without authentication. The total code is ~1.000 lines of C#.
How to use it
Eh…I will expand this section when I have some more time. You are pretty much on your own for now but you should have no problems if you are used to .NET .config files.
- Server -
The server can be xcopied to an existing ASP.NET site or you can create a new virtual directory. Edit web.config to decided which sites you want to proxy to. Add a new /configuration/appSettings key for each remote host you want to enable:
- Set the key to “host:port:“, for example “loalhost:81“
- Set the value to the users have access to to the service. Use “*“ for everyone or the user authenticated in IIS otherwise (implemented but not rested)
- Client -
Edit the provided example SocketProxy.xml file. It consists of two main sections that let you control the uplink proxies and the ports to proxy.
Proxy: The client matches the “client“ regular expression against the local IP(s) and chooses the first match. No proxy is used if there is no match. Leave user and password blank if no authentication is required.
Port: The client listens to each configured port node on the port specified in the number attribute. You can configure:
- baseUrl: the url of the ASP.NET server described earlier in this document
- remoteHost/remotePort: the remote host and port you want to proxy to
- user/password: used for basic authentication against the ASP.NET site. Use https as basic security passes the credentials in “clear text“
- clientPoll: how long to wait for a data from the client before sending an empty request if there is no data.
- noTrafficSleep: how long to wait if no data was exchanged in the last request
The last two parameters lets you tune the performance of the system.
Where can I download the code
You can download the complete source code and binaries below. As I mentioned before; the client is -very- basic as it implements the features I need. I am very happy with it as it does what it should do, I save money and I learned something new implementing it.
Let me know if you find any problems in the code or if you improve it in any way. I would like to integrate the improvements in my code or link back to site(s) with extended versions.
2006/04/06: Added Basic authentication support to the client
The server already supports Basic authentication so I added a couple of lines to the client to support it as well. Steps needed to use Basic authentication:
- Enable basic security on the web site
- Configure basic authentication on the client using the optional authentication settings
<add key="port-authentication" value="basic"/>
<add key="port-user" value="MySPClient"/>
<add key="port-password" value="whatever"/>
- Optionally configure the "allowed" setting in Web.Config. This is an optional step as you may choose to configure the user-by-user access using the security settings on the web site instead
I strongly suggest creating a user that does not have access to anything on your server apart from read/only access to the web application. This is particularly important in this basic version as the user name and password are stored in clear text in the configuration file. The application can be extended to store the credentials in protected storage or ask for them the first time they are needed but it is not a priority for me at the moment as:
- I store the app on removable storage I always keep with me
- The configured users cannot do anything on the remote systems. They can open the tunnel but they still have to authenticate against the back end system
2007/09/30: New configuration file
Updated the client with the following new features:
- Automatic proxy configuration by client IP. Changes to the client IP is detected live so there is no need to restart the client
- New parameters for tuning performance.
- Moved configuration from app.config to a .xml file in the same directory as the client. This makes the configuration easier to read and you can make changes on the fly as the file is parsed on each incoming connection.