This is a Golang implementation of the Socks5 protocol library.
To see in this SOCKS Protocol Version 5.
This library is also compatible with Socks4 and Socks4a.
- socks5:
- command: CONNECT, UDP ASSOCIATE, BIND.
- auth methods:
- Username/Password authentication.
- No Authentication Required.
- socks4:
- command: CONNECT, BIND.
- auth: (no support).
- sock4a: same as socks4.
- Custom client and server authenticator.
- Easy to read source code.
- Similar to the Golang standard library experience.
$ go get "github.com/haochen233/socks5"`
package main import ( "log" "github.com/haochen233/socks5" ) func main() { // create socks server. srv := &socks5.Server{ // socks server listen address. Addr: "127.0.0.1:1080", // UDP assocaite and bind command listen ip. // Don't need port, the port will automatically chosen. BindIP: "127.0.0.1", // if nil server will provide no authentication required method. Authenticators: nil, } // start listen err := srv.ListenAndServe() if err != nil { log.Fatal(err) } }
package main import ( "crypto/md5" "log" "github.com/haochen233/socks5" ) func main() { // create a username/password store in memory. var userStorage socks5.UserPwdStore = socks5.NewMemeryStore(md5.New(), "secret") // set a pair of username/password. userStorage.Set("admin", "123456") srv := &socks5.Server{ Addr: "127.0.0.1:1080", BindIP: "127.0.0.1", // enable username/password method and authenticator. Authenticators: map[socks5.METHOD]socks5.Authenticator{ socks5.USERNAME_PASSWORD: socks5.UserPwdAuth{UserPwdStore: userStorage}, // There is already an authentication method. // If want enable no authentication required method. // you should enable it explicit. socks5.NO_AUTHENTICATION_REQUIRED: socks5.NoAuth{}, }, } err := srv.ListenAndServe() if err != nil { log.Fatal(err) } }
package main import ( "log" "net" "github.com/haochen233/socks5" ) // simulate to impl socks5.Transporter interface. // transport encrypted data. type cryptTransport struct { } func (c *cryptTransport) TransportTCP(client *net.TCPConn, remote *net.TCPConn) <-chan error { //encrypt data and send to remote //decrypt data and send to client return nil } func (c *cryptTransport) TransportUDP(server *socks5.UDPConn, request *socks5.Request) error { panic("implement me") return nil } func main() { server := &socks5.Server{ Addr: "127.0.0.1:1080", BindIP: "127.0.0.1", // replace default Transporter interface Transporter: &cryptTransport{}, } err := server.ListenAndServe() if err != nil { log.Fatal(err) } }
package main import ( "log" "github.com/haochen233/socks5" ) func main() { // create socks client clnt := socks5.Client{ ProxyAddr: "127.0.0.1:1080", // Authenticator supported by the client. // It must not be nil. Auth: map[socks5.METHOD]socks5.Authenticator{ // If client want send NO_AUTHENTICATION_REQUIRED method to server, must // add socks5.NoAuth authenticator explicitly socks5.NO_AUTHENTICATION_REQUIRED: &socks5.NoAuth{}, }, } // client send CONNECT command and get a tcp connection. // and use this connection transit data between you and www.google.com:80. conn, err := clnt.Connect(socks5.Version5, "www.baidu.com:80") if err != nil { log.Fatal(err) } // close connection. conn.Close() }
package main import ( "fmt" "log" "github.com/haochen233/socks5" ) func main() { clnt := socks5.Client{ ProxyAddr: "127.0.0.1:1080", // client provide USERNAME_PASSWORD method and // NO_AUTHENTICATION_REQUIRED. Auth: map[socks5.METHOD]socks5.Authenticator{ socks5.NO_AUTHENTICATION_REQUIRED: &socks5.NoAuth{}, socks5.USERNAME_PASSWORD: &socks5.UserPasswd{Username: "admin", Password: "123456"}, }, } // client send UDP_ASSOCIATE command and get a udp connection. // Empty local addr string a local address (127.0.0.1:port) is automatically chosen. // you can specific a address to tell socks server which client address will // send udp data. Such as clnt.UDPForward("127.0.0.1:9999"). conn, err := clnt.UDPForward("") if err != nil { log.Fatal(err) } defer conn.Close() // send every datagram should add UDP request header. someData := []byte("some data") // dest addr where are you send to. destAddr, _ := socks5.ParseAddress("127.0.0.1:9190") // packing socks5 UDP data with dest addr. pakcedData, err := socks5.PackUDPData(destAddr, someData) // final send you data conn.Write(pakcedData) // on the contrary. // you should unpacked the packet, after received every packedData. buf := make([]byte, 65507) conn.Read(buf) // unpacking data. destAddr, unpackedData, err := socks5.UnpackUDPData(buf) // operate your udp data. fmt.Println(unpackedData) }
package main import ( "encoding/binary" "github.com/haochen233/socks5" "log" ) func main() { c := socks5.Client{ ProxyAddr: "172.16.1.28:1080", Auth: map[socks5.METHOD]socks5.Authenticator{ socks5.USERNAME_PASSWORD: &socks5.UserPasswd{"admin", "123456"}, socks5.NO_AUTHENTICATION_REQUIRED: &socks5.NoAuth{}, }, } // connect conn1, err := c.Connect(5, "127.0.0.1:9000") if err != nil { log.Fatal(err) } dest := "127.0.0.1:9001" // bind bindAddr, errors, conn2, err := c.Bind(4, dest) if err != nil { log.Fatal(err) } // An example tell dest about socks server bind address // via CONNECT proxy connection. port := make([]byte, 2) binary.BigEndian.PutUint16(port, bindAddr.Port) conn1.Write(append(bindAddr.Addr, port...)) // wait the second reply. if nil the dest already // established with socks server. err = <-errors if err != nil { log.Fatal(err) return } // bind success _, err = conn2.Write([]byte("hello")) if err != nil { return log.Fatal(err) } }
- Server default enable socks4. How to disable socks4 support?
when you initialize a socks5 server, you should spefic this flag to disable explicitly.server := &socks5.Server{ DisableSocks4: true, }