netty系列之:netty對SOCKS協議的支援

flydean發表於2022-01-06

簡介

SOCKS是一個優秀的網路協議,主要被用來做代理,它的兩個主要版本是SOCKS4和SOCKS5,其中SOCKS5提供了對認證的支援。通常來說我們使用SSH工具可以構建簡單的SOCKS協議通道,那麼對於netty來說,是怎麼提供對SOCKS的支援呢?一起來看看吧。

SocksMessage

首先是代表SOCKS訊息物件的SocksMessage。SocksMessage是一個介面,它裡面只有一個返回SocksVersion的version方法。

SocksVersion表示的是Socks的版本號。在netty中,支援三個版本,分別是:

    SOCKS4a((byte) 0x04),

    SOCKS5((byte) 0x05),

    UNKNOWN((byte) 0xff);

其對應的數值是SOCKS協議中的VER欄位,我們以SOCKS4協議為例,再複習一下SOCKS的協議結構:

含義VERCMDDSTPORTDSTIPID
位元組個數1124可變

既然netty中SOCKS有兩個版本,相對於的SocksMessage介面就有兩個實現,分別是Socks4Message和Socks5Message。

Socks4Message

Socks4Messag繼承自SocksMessage,表示的是SOCKS4的訊息。

事實上,Socks4Messag是一個tag interface,它裡面什麼內容都沒有。

public interface Socks4Message extends SocksMessage {
    // Tag interface
}

對於SOCKS4來說,有兩種資料請求型別,分別是CONNECT和BIND,這兩種請求型別被定義在Socks4CommandType中:

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

有請求就有響應,對應的有兩個類,分別是Socks4CommandRequest和Socks4CommandResponse。

對於Request來說,我們需要請求型別,USERID,DSTIP和DSTPORT這幾個資料:

    Socks4CommandType type();

    String userId();

    String dstAddr();

    int dstPort();

對於響應來說,有四個不同的狀態,分別是SUCCESS、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");

除了Socks4CommandStatus之外,響應請求還有DSTIP和DSTPORT兩個屬性。

    Socks4CommandStatus status();

    String dstAddr();

    int dstPort();

Socks5Message

同樣的,對於SOCKS5來說,也有一個對應的介面Socks5Message,這個介面也是一個Tag interface,它裡面什麼都沒有:

public interface Socks5Message extends SocksMessage {
    // Tag interface
}

對於SOCKS5來說,它的請求要比SOKCS4要複雜,首先的請求是一個初始化請求Socks5InitialRequest,該請求包含了可以接受的認證列表。

這個列表用Socks5AuthMethod來表示,它包含4個方法:

    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");

對於Socks5InitialRequest來說,它包含了一個authMethods的列表:

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

對於InitialRequest來說,對應的也有Socks5InitialResponse,它包含了服務端選擇的Socks5AuthMethod,所以對Socks5InitialResponse來說,它裡面只包含了一個Socks5AuthMethod:

public interface Socks5InitialResponse extends Socks5Message {

    Socks5AuthMethod authMethod();
}

客戶端和伺服器端協商好選擇的認證協議之後,接下來就是認證的過程,如果使用的是使用者名稱密碼的模式,則對應的是Socks5PasswordAuthRequest:

public interface Socks5PasswordAuthRequest extends Socks5Message {

    String username();

    String password();
}

password認證的結果只有兩種結果,分別是SUCCESS和FAILURE:

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

對於Socks5PasswordAuthResponse來說,它包含了一個認證的status:Socks5PasswordAuthStatus。

認證完畢之後,接下來就可以傳送CommandRequest了。對應的Socks5CommandRequest包含下面幾個屬性:

    Socks5CommandType type();

    Socks5AddressType dstAddrType();

    String dstAddr();

    int dstPort();

對應的Socks5CommandResponse包含下面的屬性:

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

總結

以上就是netty對SOCKS4和SOCKS5協議的訊息封裝。基本上netty中的物件是和SOCKS協議一致的。

本文已收錄於 http://www.flydean.com/36-netty-socks-support/

最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!

相關文章