socks5 is a Go library whose types mirror the SOCKS5 protocol
SOCKS Protocol Version 5 Library in Go. Full TCP/UDP and IPv4/IPv6 support
At a glance
- What is it?
- txthinking/socks5 is a Go implementation of SOCKS Protocol Version 5 with full TCP, UDP and IPv4, IPv6 support, written so that the structs correspond to the protocol's own messages. It is a library rather than a proxy binary, MIT licensed, with a small API and a classic server and client for the common case.
- Who is it for?
- Go developers who need to speak the SOCKS5 protocol, either to implement a server or to speak through a proxy from a client, should use this library, because the type names correspond to the protocol messages and the dependencies are three, which keeps a protocol implementation small enough to audit.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 144 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A library shaped like the specification
socks5 is a SOCKS Protocol Version 5 library in Go, with full TCP, UDP and IPv4, IPv6 support.
The design goal is stated in one line and it is the most useful thing in the README: KISS, less is more, small API, code is like the original protocol. The library's headline section is literally titled Struct is like concept in protocol, and that is the organising principle. Rather than hiding the protocol behind a convenience API, it names its types after the messages on the wire, so a developer reading the RFC and the package side by side sees the same vocabulary.
The type surface is short. There is a NegotiationRequest with a NegotiationReply for the method selection at the start of a connection, a UserPassNegotiationRequest with a UserPassNegotiationReply for the username and password exchange, then a Request and a Reply for the actual connection request, and a Datagram for the UDP associate form.
Each of them follows the same pattern. A New function builds the structure, a WriteTo method writes it to an io.Writer, and a From constructor reads it back from an io.Reader. The README even marks which side each one belongs to, with notes such as in client and in server, so there is no ambiguity about who writes and who reads.
The audience is Go developers implementing the protocol themselves, either on the server side or the client side, and the project's own homepage is txthinking.com. The last push was on 2026-06-01, and the repository publishes no GitHub releases.
Five message types, and the order they arrive in
The mapping between the API and the protocol is exact, and walking the connection once makes it clear.
A connection starts with negotiation. The client calls NewNegotiationRequest with a list of method bytes and writes it to the server; the server calls NewNegotiationRequestFrom to read it. The server answers with NewNegotiationReply for a chosen method, and the client reads that with NewNegotiationReplyFrom.
If the chosen method is user and password authentication, the same pattern repeats with UserPassNegotiationRequest and UserPassNegotiationReply, where the request carries the username and password byte slices and the reply carries a status byte. After the negotiation succeeds, the client sends a Request, which carries a command byte, an address type byte, the destination address bytes and the destination port bytes, and the server replies with a Reply carrying its own address type, bound address and bound port.
The Datagram type is the UDP side. It is constructed with NewDatagram from an address type, destination address, destination port and the data, read from a byte slice with NewDatagramFromBytes, and serialised with a Bytes method.
Two details in the API are worth noticing. The address and port are passed as byte slices rather than as net.IP and int, which keeps the types protocol-level and avoids the library deciding how to encode an address for you. And the Request constructor takes a command byte, so the type covers CONNECT and the other command codes without the library having to interpret them.
The library also does not hide the order of operations: the README annotates each step with which peer writes and which peer reads, so the handshake is legible from the type names alone.
The advanced API for the common server and client case
Behind the message types there is a second, more convenient API, and the README is careful about how it presents it. It says this can satisfy the classic scenario, and it is still recommended that you choose the small API above to customize for special scenarios.
On the server side there is a Server struct and a Handler interface with two methods:
type Handler interface
TCPHandle(*Server, *net.TCPConn, *Request) error
UDPHandle(*Server, *net.UDPAddr, *Datagram) errorThe server is constructed with NewClassicServer, taking an address, an ip, a username, a password, a TCP timeout and a UDP timeout, and is then run with ListenAndServe and your handler:
server, _ := NewClassicServer(addr, ip, username, password, tcpTimeout, udpTimeout)
server.ListenAndServe(Handler)The client mirrors it. There is a Client struct, built with NewClassicServer's client counterpart socks5.NewClient, taking the server address, credentials and the two timeouts, and it returns a net.Conn from Dial:
client, _ := socks5.NewClient(server, username, password, tcpTimeout, udpTimeout)
conn, _ := client.Dial(network, addr)The point of that last line is that the client returns a net.Conn. Once you have it, everything above it, your HTTP client, your database driver or your own protocol, treats the proxy as a plain connection and never learns there is a proxy in the way. The same holds for the server, where the handler receives a *net.TCPConn and can read and write it as it would a socket.
That is the difference between the two APIs in one sentence: the small API gives you the bytes, the advanced API gives you a connection, and the project recommends the first when your scenario is unusual.
Three dependencies and a Go 1.16 floor
The go.mod is short, which is unusual for a networking library and worth reading as a signal about the design.
module github.com/txthinking/socks5
go 1.16
require (
github.com/miekg/dns v1.1.51
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf
)There is no TLS library, no HTTP framework and no logging framework. A SOCKS5 implementation needs a DNS resolver to look up destination names, which is what miekg/dns provides, a cache to avoid resolving the same name on every request, which is go-cache, and a runner group to manage the goroutine set of a running server, which is the author's own runnergroup package.
The Go 1.16 floor is the other detail. It is a low floor for a module published in this era, which means the library builds on toolchains that have long been out of support, and that it will keep building as Rust and Go toolchains move on. For a library that does byte-level protocol work and is not expected to gain dependencies, that is a reasonable place to stand.
The repository layout matches the file names of the protocol, with client.go, client_side.go, server.go, server_side.go, connect.go, udp.go, init.go, bind.go, socks5.go and util.go at the root, plus tests for the client dialer, an example test and a util test.
The projects that depend on it
The README lists the projects using this library, and it is a good argument for the design decisions being sensible rather than merely minimal.
The list includes Brook, which is by the same author, Shiliew, dismap, emp3r0r, hysteria, mtg and trojan-go.
These are all proxy or tunnelling systems, and that tells you something about what the library is for. hysteria is a proxy built for adversarial network conditions, trojan-go is a proxy that disguises its traffic, mtg is a Shadowsocks-style proxy server, and emp3r0r is a penetration testing toolkit that includes a proxy. What they share is a need for a SOCKS5 client or server that behaves predictably and adds nothing else.
That is the strongest argument for the KISS goal. A protocol library that ends up inside a traffic anonymiser, a censorship circumvention tool and a red team toolkit at the same time cannot afford a large dependency tree or a surprising API, because every one of those consumers needs the wire behaviour to be exactly the specification and nothing more.
It also explains the choice to expose the raw message types. A consumer in that category often needs to bend one detail of the protocol, and the small API lets them do that without forking the library.
The project is MIT licensed, and the README links a Chinese translation of the same page along with the author's news channel and YouTube channel, which suggests a primarily Chinese-speaking user base.
Where socks5 is the wrong tool
The limits are the ones a protocol library has by definition.
First, it is a library and not a program. There is no binary to install, no configuration file, no service unit and no command line. If you want a proxy running on a server, you either write the fifty lines that use this library or you look for a project that ships a binary, and several of the projects in the README's own list do exactly that.
Second, the documented authentication is the user and password method only. The negotiation step can select a method, and the user and password exchange is the one the README details, so a deployment that needs a different authentication scheme has work to do at the message level. The README does not describe an extension point for adding one.
Third, the go.mod shows a Go 1.16 floor, which is a double-edged fact. It means the library will build almost anywhere, and it also means it predates a decade of language and standard library work, including the generics that a modern codebase might expect to use around it. That is fine for a protocol library and awkward for a team whose own code is on a much newer baseline.
Finally, there is no version history to pin. The repository publishes no GitHub releases, so a consumer tracks a branch, and the dependency list pins a runnergroup version by commit hash, which is the same idea in smaller form.
For what it is, a small and legible protocol implementation with three dependencies, this is exactly the right shape, and the list of downstream projects is the evidence.
Editorial conclusion
Go developers who need to speak the SOCKS5 protocol, either to implement a server or to speak through a proxy from a client, should use this library, because the type names correspond to the protocol messages and the dependencies are three, which keeps a protocol implementation small enough to audit. It is the wrong tool if you want a ready-made proxy command, since the repository ships no binary and no configuration file, and it is the wrong choice if you need features the protocol does not cover. Before adopting, read the protocol mapping in the README and confirm the authentication method your deployment uses, because only user and password negotiation is covered in the documented API.
Frequently asked questions
How do I install the socks5 Go library?
Run go get github.com/txthinking/socks5. The module declares Go 1.16 as its language version and pulls in three dependencies: miekg/dns, patrickmn/go-cache and txthinking/runnergroup.
How does the socks5 library structure the protocol messages?
One struct per protocol message: NegotiationRequest and NegotiationReply, UserPassNegotiationRequest and UserPassNegotiationReply, Request and Reply, and Datagram for the UDP form. Each has a constructor, a WriteTo for the writing side and a From constructor that reads it from an io.Reader.
Does the socks5 library support UDP and IPv6?
Yes. The description states full TCP, UDP and IPv4, IPv6 support, and the server side exposes both a TCPHandle and a UDPHandle method on its Handler interface.
What licence is the socks5 library under?
The MIT License, as the README states directly and as the LICENSE file in the repository root records.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/txthinking-socks5)Was this useful?