A simple Golang implementation of the HTTP Proxy

Source: Internet
Author: User
Tags vps
This is a creation in Article, where the information may have evolved or changed.

Recently, because of the Mac, the previous Linux is basically no longer used, but my SS agent has to use. SS Agent We all know, a very NB Socket Agent tool, but is because he is the socket, want to use HTTP proxy when very inconvenient.

In the previous time under Linux, will install a privoxy to switch the socket proxy to HTTP proxy, boot start, also more convenient. But it's hard to use a brew-installed privoxy under a Mac, plus a previous idea, a software that makes sockets and HTTP proxies, so you don't have to install a separate software to do the conversion.

Think about the beginning to do, before basically did not make too much network programming, recently also just in the study go, just practice practiced hand.

Here we mainly talk about using the Connect method in the http/1.1 protocol to set up the tunnel connection, the implementation of the HTTP Proxy. The advantage of this agent is not to know the client request data, only need to be left intact forwarding, for the processing of HTTPS request is very convenient, do not have to parse his content, you can implement the agent.

Start agent Monitoring

To make an HTTP proxy, we need to start a server and listen to a port to receive requests from clients. Golang provides us with a powerful net package for our use, and it is very convenient for us to start a proxy server for monitoring.

1234
L, Err: = Net. Listen ("tcp"": 8080")ifnil {log. Panic (ERR)}

Above agent we have implemented a 8080 port on the monitoring of the server, we do not write an IP address, the default on all IP addresses to listen. If you only want to apply this machine, you can use 127.0.0.1:8080, so the machine will not be able to access your proxy server.

Listening to receive agent requests

Start the proxy server, you can begin to accept the proxy request, with the request, we can do further processing.

12345678
 for {client, err: = L.accept ()ifnil {log. Panic (ERR)}go handleclientrequest (client)}

The Accept method of the Listener interface accepts the connection data sent by the client, which is a blocking method, and if the client does not have the connection data sent, he is blocking the wait. The received connection data will be handed over to the Handleclientrequest method for processing, where a go keyword is used to open a goroutine to not block the reception of the client, the proxy server can immediately receive the next connection request.

Parse the request to get the IP and port to access

With the client's proxy request, we also have to extract from the request the client to access the remote host IP and port, so that our proxy server can establish and remote host connection, proxy forwarding.

The header information of the HTTP protocol contains the hostname (IP) and port information we need, and it is clear, and the protocol is very canonical, similar to the following:

1234
CONNECT www.google.com:443 http/1.1host:www.google.com:443proxy-connection:keep-aliveuser-agent:mozilla/5.0 ( Macintosh; Intel Mac OS X 10_12_0) applewebkit/537.36 (khtml, like Gecko) chrome/55.0.2883.95 safari/537.36

Can see what we need in the first line, the first line of information is separated by a space, the first part of Connect is the request method, here is connect, in addition to Get,post, etc., are the standard method of the HTTP protocol.

The second part is the request of Url,https only host and Port,http request is a completed URL, and so will look at a sample, you understand.

The third part is the HTTP protocol and version, which we don't have to pay much attention to.

The above is an HTTPS request, we look at the http:

12345
GET http://www.flysnow.org/HTTP/1.1Host:www.flysnow.orgProxy-Connection:keep-aliveUpgrade-Insecure-Requests: 1user-agent:mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) applewebkit/537.36 (khtml, like Gecko) chrome/55.0.2883.95 safari/537.36

You can see the HTT, no port number (default is 80), more than HTTPS schame–http://.

With the analysis, we can get the requested URL and method information from the HTTP header information.

12345678910111213
var b [1024x768]byten, Err: = client. Read (b[:])ifnil {log. PRINTLN (Err)return}varstringfmt. SSCANF (string' \ n '"%s%s", &method, &host) Hostporturl, err: = URL. Parse (host)ifnil {log. PRINTLN (Err)return}

Then we need to parse the URL further to get the remote server information we need.

123456789
if "443" //https Access ": 443" Else //http Access if ":" -1 //host without port, default ":" Else {address = Hostporturl.host}}

This is complete. Gets the information to request the server, they may be in the following formats

123
Ip:porthostname:portdomainname:port

is the possible IP (V4ORV6), may be the hostname (intranet), may be the domain name (DNS resolution)

Proxy server and remote server establish connection

With the remote server information, you can dial to establish a connection, there is a connection, you can communicate.

123456
//received the requested host and port, start dialing the server, err: = Net. Dial ("TCP", address)ifnil {log. PRINTLN (Err)return}

Data forwarding

After the dial is successful, the data agent can be transferred.

12345678
if "CONNECT" "http/1.1 Connection established\r\n\r\n" Else {Server. Write (B[:n])}//To forward go io. Copy (server, client) IO. Copy (client, server)

The Connect method has a separate response, the client said to establish a connection, the proxy server to respond to the establishment, and then can be like HTTP request access.

Running foreign VPS on the outside

Here, our proxy server all developed, the following is the complete source code:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 666768697071727374
 PackageMainImport("bytes""FMT""IO""Log""NET""Net/url""Strings") func main() {log. SetFlags (log. Lstdflags|log. Lshortfile) L, err: = Net. Listen ("TCP",": 8081")ifErr! =Nil{log. Panic (ERR)} for{client, err: = L.accept ()ifErr! =Nil{log. Panic (ERR)}GoHandleclientrequest (client)}} func handleclientrequest(client net. Conn) {ifClient = =Nil{return}deferClient. Close ()varb [1024x768]byteN, Err: = client. Read (b[:])ifErr! =Nil{log. PRINTLN (ERR)return}varmethod, host, addressstringFmt. SSCANF (string(B[:bytes. Indexbyte (b[:],' \ n ')]),"%s%s", &method, &host) Hostporturl, err: = URL. Parse (host)ifErr! =Nil{log. PRINTLN (ERR)return}ifHostporturl.opaque = ="443"{//https AccessAddress = Hostporturl.scheme +": 443"}Else{//http AccessifStrings. Index (Hostporturl.host,":") ==-1{//host without port, defaultAddress = Hostporturl.host +":"}Else{address = Hostporturl.host}}//Get the requested host and port, start dialingServer, Err: = Net. Dial ("TCP", address)ifErr! =Nil{log. PRINTLN (ERR)return}ifmethod = ="CONNECT"{FMT. Fprint (Client,"http/1.1 Connection established\r\n\r\n")}Else{Server. Write (B[:n])}//To forwardGoIo. Copy (server, client) IO. Copy (client, server)}

Compile the source code, and then put it on your foreign VPS, configure the HTTP proxy on your own machine, you can 到处 access, free.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.