Netty series: netty's support for SOCKS protocol

Posted by gojakie on Thu, 06 Jan 2022 03:08:56 +0100

brief introduction

SOCKS is an excellent network protocol, which is mainly used as an agent. Its two main versions are SOCKS4 and SOCKS5, in which SOCKS5 provides support for authentication. Generally speaking, we can use SSH tools to build a simple SOCKS protocol channel. How does netty support SOCKS? Let's have a look.

SocksMessage

The first is the SocksMessage representing the SOCKS message object. SocksMessage is an interface with only one version method that returns SocksVersion.

SocksVersion indicates the version number of Socks. In netty, three versions are supported:

    SOCKS4a((byte) 0x04),

    SOCKS5((byte) 0x05),

    UNKNOWN((byte) 0xff);

The corresponding value is the VER field in SOCKS protocol. Let's take SOCKS4 protocol as an example and review the protocol structure of SOCKS:

meaningVERCMDDSTPORTDSTIPID
Number of bytes1124variable

Since there are two versions of SOCKS in netty, there are two implementations relative to the SocksMessage interface, namely Socks4Message and Socks5Message.

Socks4Message

Socks4Messag inherits from SocksMessage and represents the message of SOCKS4.

In fact, Socks4Messag is a tag interface, which contains nothing.

public interface Socks4Message extends SocksMessage {
    // Tag interface
}

For SOCKS4, there are two data request types, CONNECT and BIND, which are defined in Socks4CommandType:

    public static final Socks4CommandType CONNECT = new Socks4CommandType(0x01, "CONNECT");
    public static final Socks4CommandType BIND = new Socks4CommandType(0x02, "BIND");

There are two corresponding classes: Socks4CommandRequest and Socks4CommandResponse.

For Request, we need the data of Request type, USERID, DSTIP and DSTPORT:

    Socks4CommandType type();

    String userId();

    String dstAddr();

    int dstPort();

For response, there are four different states: SUCCESS and REJECTED_OR_FAILED,IDENTD_UNREACHABLE,IDENTD_AUTH_FAILURE.

    public static final Socks4CommandStatus SUCCESS = new Socks4CommandStatus(0x5a, "SUCCESS");
    public static final Socks4CommandStatus REJECTED_OR_FAILED = new Socks4CommandStatus(0x5b, "REJECTED_OR_FAILED");
    public static final Socks4CommandStatus IDENTD_UNREACHABLE = new Socks4CommandStatus(0x5c, "IDENTD_UNREACHABLE");
    public static final Socks4CommandStatus IDENTD_AUTH_FAILURE = new Socks4CommandStatus(0x5d, "IDENTD_AUTH_FAILURE");

In addition to Socks4CommandStatus, the response request also has two attributes: DSTIP and DSTPORT.

    Socks4CommandStatus status();

    String dstAddr();

    int dstPort();

Socks5Message

Similarly, for SOCKS5, there is also a corresponding interface Socks5Message, which is also a Tag interface. There is nothing in it:

public interface Socks5Message extends SocksMessage {
    // Tag interface
}

For SOCKS5, its request is more complex than SOKCS4. The first request is an initialization request Socks5InitialRequest, which contains an acceptable authentication list.

This list is represented by Socks5AuthMethod, which contains four methods:

    public static final Socks5AuthMethod NO_AUTH = new Socks5AuthMethod(0x00, "NO_AUTH");
    public static final Socks5AuthMethod GSSAPI = new Socks5AuthMethod(0x01, "GSSAPI");
    public static final Socks5AuthMethod PASSWORD = new Socks5AuthMethod(0x02, "PASSWORD");
    public static final Socks5AuthMethod UNACCEPTED = new Socks5AuthMethod(0xff, "UNACCEPTED");

For Socks5InitialRequest, it contains a list of authMethods:

public interface Socks5InitialRequest extends Socks5Message {
    List<Socks5AuthMethod> authMethods();
}

For InitialRequest, there is also Socks5InitialResponse, which contains the Socks5AuthMethod selected by the server. Therefore, for Socks5InitialResponse, it contains only one Socks5AuthMethod:

public interface Socks5InitialResponse extends Socks5Message {

    Socks5AuthMethod authMethod();
}

After the client and server negotiate the selected authentication protocol, the next step is the authentication process. If the user name and password mode is used, the corresponding is Socks5PasswordAuthRequest:

public interface Socks5PasswordAuthRequest extends Socks5Message {

    String username();

    String password();
}

There are only two results of password authentication, SUCCESS and FAILURE:

    public static final Socks5PasswordAuthStatus SUCCESS = new Socks5PasswordAuthStatus(0x00, "SUCCESS");
    public static final Socks5PasswordAuthStatus FAILURE = new Socks5PasswordAuthStatus(0xFF, "FAILURE");

For Socks5PasswordAuthResponse, it contains an authentication status: Socks5PasswordAuthStatus.

After authentication, you can then send a CommandRequest. The corresponding Socks5CommandRequest contains the following attributes:

    Socks5CommandType type();

    Socks5AddressType dstAddrType();

    String dstAddr();

    int dstPort();

The corresponding Socks5CommandResponse contains the following attributes:

    Socks5CommandStatus status();
    Socks5AddressType bndAddrType();
    String bndAddr();
    int bndPort();

summary

The above is the message encapsulation of netty for SOCKS4 and SOCKS5 protocols. Basically, the objects in netty are consistent with the SOCKS protocol.

This article has been included in http://www.flydean.com/36-netty-socks-support/

The most popular interpretation, the most profound dry goods, the most concise tutorial, and many tips you don't know are waiting for you to find!

Welcome to my official account: "those things in procedure", understand technology, know you better!

Topics: Java Netty socks5