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.