This is a creation in Article, where the information may have evolved or changed.
In the celestial programmer compared to make people egg pain, such as you want to use Google, you are very painful. We all know why.
Then, the beginning of their own in the use of Goagent, VPN, SSH, shadowsocks and other programs, goagent and Shadowsocks are very excellent. When I first started to touch the computer, I had the idea to write an agent, because all kinds of reasons are always not to do, or that their needs can always be satisfied, so there is no motivation. But since learning the go language, the development of the network program has not been done before C + + when the egg hurts, so try to write a proxy program, and then also implement eating your own dog food practice. Here is a summary of some of the notes. GitHub Address: Https://github.com/eahydra/socks
SOCKS5 protocol
At the beginning, is to do HTTP proxy, but the HTTP protocol is more complex, the concept of more involved, and not familiar with themselves, so there is no way to select the HTTP channel agent. And the most used in the agency agreement is actually the socks agreement. Socks4,socks5 and so on. Because I have been using Chrome, chrome plug-in Switchysharp is also more useful, also support the SOCKS5 protocol, more importantly, SOCKS5 protocol is very simple.
SOCKS5 agreement is mainly divided into three steps, the first step is the handshake negotiation, the negotiation of the two sides of the verification method. My approach is simple and rude: because the SOCKS5 defined in the handshake protocol, the maximum data length is 258 direct, so I am in the implementation of the time, the direct application of 258 bytes of buffer, and then read. After reading also does not determine whether the authentication method is legitimate, support and so on, directly return 0x05 0x00, that is, do not need to verify.
The second step is to get the CMD protocol sent by the client. SOCKS5 here also specifies the maximum length, 263 bytes. So I applied for it once again for later use. Thanks to the Go Language Package network library, no matter what domain name, or Ipv4,ipv6, and so on, call net. It's good to be in the dial, net. The dial function internally will fix itself to the IP conversion. The corresponding protocol data is then returned according to the target address link specified in cmd. At the moment I only support connect, like UDP and so on did not do support, encountered a UDP command directly tell the client is not supported, and then disconnect the link.
The third step is to start accepting the data sent by the client and then send it to the remote server, then read the data from the remote server and forward it to the client. This is easy, just two lines of code to get it done.
Go IO. Copy (dest, src) io. Copy (SRC, dest)
Deployment
Once the program is written, it has to be deployed. Thanks to Amazon for providing a free year of AWS Services. How to apply such a self-search solution. The portability of Go is reflected here because I developed it under windows and then deployed to Ubuntu on AWS, a go build was done. Then the program runs, setting Switchysharp directly to AWS, with significant results. But in the middle of the test, found that the link to the http://go-talks.appspot.com/github.com/extemporalgenome/gotalks/error-handling.slide#1 is not, catch bag found , a lot of RST was sent from AWS, but my program didn't print out the corresponding close information. This time I guess what it should be (you know) doing content detection, one of the ways to solve is to encrypt. So I did the encryption function behind it.
Encryption
Adding encryption to the egg hurts, because I probably don't just want a cryptographic algorithm, maybe this will want to use RC4, and then I want to use AES or DES. There is also how to encapsulate cryptographic algorithms so that they have less impact on existing code. Originally I wanted to manually package it into IO. Reader and Io.writer interface, so that you can form a call chain, it is natural to the network data encryption and decryption. Then I went to go to the standard library, there are encryption algorithms, Rc4,des,aes are provided, and then there is a packet called Crypto/cipher, this package provides two interfaces, a call Streamread, another called Streamwrite, these two interfaces just can meet IO . Reader and Io.write. That's a lot easier. The specific code is as follows (the code does not do what the Factory mode, because it is not necessary to write a simple brute point will not affect the other code):
Func newcipherstream (RWC io. Readwritecloser, Cryptmethodstring, Password []byte) (*Cipherstream, error) { varStream *CipherstreamSwitchCryptmethod {default: Stream= &cipherstream{READER:RWC, WRITECLOSER:RWC,} Case "RC4": {rc4cipherread, err:=RC4. Newcipher (password)ifErr! =Nil {returnnil, err} rc4cipherwrite, err:=RC4. Newcipher (password)ifErr! =Nil {returnnil, err} stream= &cipherstream{Reader:&cipher. streamreader{s:rc4cipherread, R:RWC,}, Writecloser : &cipher. streamwriter{s:rc4cipherwrite, W:RWC,},}} Case "des": {block, err:=des. Newcipher (password)ifErr! =Nil {returnnil, err} desread:=cipher. Newcfbdecrypter (block, desiv[:]) Deswrite:=cipher. Newcfbencrypter (block, desiv[:])return&cipherstream{Reader:&cipher. streamreader{s:desread, R:RWC,}, Writecloser: &cipher. streamwriter{s:deswrite, W:RWC,},}, nil}} returnstream, nil}
If you do not specify an encryption method or an unsupported encryption method, use the original IO. Reader and Io.writer interface. This can reduce the impact on the upper layer.
Because of the support for multiple encryption methods, the configuration file is used. This is very simple, the direct JSON format is done.
Another problem is that the browser only recognizes the SOCKS protocol, you now add encryption, then you have to hide the browser, and then you have to support two modes, one mode is the local socks run mode, to the browser, another mode is to the remote Socks service data to be encrypted. Originally wanted to write a local socks, but think, it is unnecessary, because most of the functions of this program can be satisfied on the basis of existing code, then one way is to copy the code, but I have to maintain two points, the other way is to change the original code. Decide to change the existing code, nothing more than the client's request to come, first link to their remote Socks service, and then provide data transfer service. This involves the question of how to interact with the remote service.
Solutions for interacting with remote socks
In order to solve this problem, we need to make a contract. Is it necessary to increase the agreement? My first thought seemed unnecessary, and the second thought was really unnecessary. It's really not necessary! Because SOCKS5 's protocol is sufficient, I don't want to add a set of additional protocols to the remote, and this protocol will eventually be similar to SOCKS5, and the code will be very painful to implement. So decided to use the SOCKS5 protocol as a form of a call chain. The client comes to the handshake, and the local socks also to the remote socks on the handshake. The cmd sent by the client is forwarded directly to the remote socks. Then the middle goes encrypted. This realization becomes very simple. Defines a struct remotesocks, anonymously combines the *cipherstream so that it can go directly encrypted. The specific definition code is as follows:
struct { conn net. Conn *Cipherstream}
Then sync the code to AWS, compile and run, and find it smooth. To the base friend Dog Eye Kun shared the next, encountered a bug, on his machine linked to YouTube link error. Then think about the question where, start to do code review, find their own implementation of the encryption part, RC4 related to the partial read and write the same encrypted object, and then this object is not thread-safe, the problem should be here, fix it, and then test, OK.
Summarize
Always have their own agent program, use it very happy, because it is done by himself! Eating your own dog food is very important. When you implement a program, you can not take a big step at a time, so easy to pull eggs, you can come a little.