├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .gitignore ├── README.adoc ├── SECURITY.md ├── handler-proxy ├── src │ ├── test │ │ └── java │ │ │ └── io │ │ │ └── netty │ │ │ └── contrib │ │ │ └── handler │ │ │ └── proxy │ │ │ ├── TestMode.java │ │ │ ├── NativeImageHandlerMetadataTest.java │ │ │ └── UnresponsiveHandler.java │ └── main │ │ ├── java │ │ └── io │ │ │ └── netty │ │ │ └── contrib │ │ │ └── handler │ │ │ └── proxy │ │ │ ├── package-info.java │ │ │ ├── ProxyConnectException.java │ │ │ └── ProxyConnectionEvent.java │ │ └── resources │ │ └── META-INF │ │ └── native-image │ │ └── io.netty.contrib │ │ └── netty-handler-proxy │ │ └── generated │ │ └── handlers │ │ └── reflect-config.json └── pom.xml ├── codec-socks ├── src │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── netty │ │ │ └── contrib │ │ │ └── handler │ │ │ └── codec │ │ │ ├── socks │ │ │ ├── package-info.java │ │ │ ├── SocksMessageType.java │ │ │ ├── SocksRequestType.java │ │ │ ├── SocksResponseType.java │ │ │ ├── UnknownSocksRequest.java │ │ │ ├── UnknownSocksResponse.java │ │ │ ├── SocksAuthStatus.java │ │ │ ├── SocksCmdType.java │ │ │ ├── SocksProtocolVersion.java │ │ │ ├── SocksSubnegotiationVersion.java │ │ │ ├── SocksAddressType.java │ │ │ ├── SocksAuthScheme.java │ │ │ ├── SocksCmdStatus.java │ │ │ ├── SocksRequest.java │ │ │ ├── SocksResponse.java │ │ │ ├── SocksMessageEncoder.java │ │ │ ├── SocksInitResponse.java │ │ │ ├── SocksAuthResponse.java │ │ │ ├── SocksInitRequest.java │ │ │ ├── SocksCommonUtils.java │ │ │ ├── SocksMessage.java │ │ │ ├── SocksInitResponseDecoder.java │ │ │ ├── SocksAuthResponseDecoder.java │ │ │ ├── SocksInitRequestDecoder.java │ │ │ ├── SocksAuthRequest.java │ │ │ └── SocksAuthRequestDecoder.java │ │ │ └── socksx │ │ │ ├── package-info.java │ │ │ ├── v4 │ │ │ ├── package-info.java │ │ │ ├── Socks4Message.java │ │ │ ├── AbstractSocks4Message.java │ │ │ ├── Socks4CommandResponse.java │ │ │ ├── Socks4CommandRequest.java │ │ │ ├── Socks4ServerEncoder.java │ │ │ ├── Socks4CommandType.java │ │ │ ├── Socks4ClientEncoder.java │ │ │ ├── Socks4CommandStatus.java │ │ │ ├── DefaultSocks4CommandResponse.java │ │ │ ├── Socks4ClientDecoder.java │ │ │ └── DefaultSocks4CommandRequest.java │ │ │ ├── v5 │ │ │ ├── package-info.java │ │ │ ├── Socks5Message.java │ │ │ ├── Socks5InitialResponse.java │ │ │ ├── Socks5PasswordAuthResponse.java │ │ │ ├── AbstractSocks5Message.java │ │ │ ├── Socks5InitialRequest.java │ │ │ ├── Socks5PasswordAuthRequest.java │ │ │ ├── Socks5CommandRequest.java │ │ │ ├── Socks5CommandResponse.java │ │ │ ├── DefaultSocks5InitialResponse.java │ │ │ ├── DefaultSocks5PasswordAuthResponse.java │ │ │ ├── Socks5AddressEncoder.java │ │ │ ├── Socks5CommandType.java │ │ │ ├── Socks5AddressType.java │ │ │ ├── Socks5PasswordAuthStatus.java │ │ │ ├── DefaultSocks5InitialRequest.java │ │ │ ├── Socks5AuthMethod.java │ │ │ ├── Socks5AddressDecoder.java │ │ │ ├── DefaultSocks5PasswordAuthRequest.java │ │ │ ├── Socks5PasswordAuthResponseDecoder.java │ │ │ ├── Socks5InitialResponseDecoder.java │ │ │ ├── Socks5InitialRequestDecoder.java │ │ │ ├── Socks5PasswordAuthRequestDecoder.java │ │ │ ├── DefaultSocks5CommandRequest.java │ │ │ ├── Socks5CommandStatus.java │ │ │ └── Socks5ServerEncoder.java │ │ │ ├── SocksMessage.java │ │ │ ├── AbstractSocksMessage.java │ │ │ └── SocksVersion.java │ └── test │ │ └── java │ │ └── io │ │ └── netty │ │ └── contrib │ │ └── handler │ │ └── codec │ │ ├── socks │ │ ├── SocksAuthResponseTest.java │ │ ├── SocksInitRequestTest.java │ │ ├── SocksInitResponseTest.java │ │ ├── SocksCommonTestUtils.java │ │ ├── SocksAuthResponseDecoderTest.java │ │ ├── SocksAuthRequestDecoderTest.java │ │ └── SocksAuthRequestTest.java │ │ ├── socksx │ │ ├── v5 │ │ │ ├── DefaultSocks5InitialRequestTest.java │ │ │ ├── DefaultSocks5InitialResponseTest.java │ │ │ ├── DefaultSocks5PasswordAuthResponseTest.java │ │ │ ├── Socks5PasswordAuthRequestDecoderTest.java │ │ │ ├── Socks5InitialRequestDecoderTest.java │ │ │ ├── Socks5CommonTestUtils.java │ │ │ ├── Socks5PasswordAuthResponseDecoderTest.java │ │ │ ├── DefaultSocks5PasswordAuthRequestTest.java │ │ │ └── DefaultSocks5CommandRequestTest.java │ │ └── v4 │ │ │ ├── Socks4CommonTestUtils.java │ │ │ ├── Socks4ClientDecoderTest.java │ │ │ └── Socks4ServerDecoderTest.java │ │ └── NativeImageHandlerMetadataTest.java └── pom.xml ├── .github └── workflows │ ├── release.yml │ └── ci-build.yml ├── examples ├── pom.xml └── src │ └── main │ └── java │ └── io │ └── netty │ └── contrib │ └── handler │ └── codec │ └── example │ └── socksproxy │ ├── SocksServerUtils.java │ ├── SocksServerInitializer.java │ ├── DirectClientHandler.java │ ├── RelayHandler.java │ └── SocksServer.java └── NOTICE.txt /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netty-contrib/socks-proxy/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://maven-central.storage-download.googleapis.com/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | .settings 4 | *.iml 5 | *.ipr 6 | *.iws 7 | .idea/ 8 | .shelf/ 9 | target/ 10 | .DS_Store 11 | hs_err_pid*.log 12 | dependency-reduced-pom.xml 13 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Netty 5.x SOCKS Codec and Handler Repository for Netty Contrib 2 | 3 | * Netty core repository: https://github.com/netty/netty 4 | * License: Apache-2.0 License 5 | * Required Java version: Java 11 6 | * Maven coordinates: 7 | ** `io.netty.contrib:netty-socks-proxy:5.0.0.Final-SNAPSHOT` 8 | 9 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The following versions of this library are supported: 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 5.0.x | :white_check_mark: | 10 | | < 5.0 | :x: | 11 | 12 | Older versions, for use with Netty 4.1, are located in the Netty repository. 13 | 14 | ## Reporting a security issue 15 | 16 | If you think the bug you found is likely to make Netty-based applications vulnerable to an attack, 17 | please do not use our public issue tracker 18 | but report it to [the dedicated private Google Group](https://groups.google.com/d/forum/netty-security). 19 | -------------------------------------------------------------------------------- /handler-proxy/src/test/java/io/netty/contrib/handler/proxy/TestMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.proxy; 17 | 18 | enum TestMode { 19 | INTERMEDIARY, 20 | TERMINAL, 21 | UNRESPONSIVE, 22 | } 23 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | /** 18 | * Encoder, decoder and their related message types for Socks. 19 | */ 20 | package io.netty.contrib.handler.codec.socks; 21 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | /** 18 | * Encoder, decoder and their related message types for SOCKS protocol. 19 | */ 20 | package io.netty.contrib.handler.codec.socksx; 21 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksMessageType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | public enum SocksMessageType { 19 | REQUEST, 20 | RESPONSE, 21 | UNKNOWN 22 | } 23 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | /** 18 | * Encoder, decoder and their related message types for SOCKSv4 protocol. 19 | */ 20 | package io.netty.contrib.handler.codec.socksx.v4; 21 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | 17 | /** 18 | * Encoder, decoder and their related message types for SOCKSv5 protocol. 19 | */ 20 | package io.netty.contrib.handler.codec.socksx.v5; 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | version: 6 | description: 'The version being released (pom.xml files will be updated) - leave empty for Maven default' 7 | required: false 8 | type: string 9 | default: '' 10 | netty: 11 | description: 'The version range to use for the Netty Core dependencies - will use value from pom.xml if empty' 12 | required: false 13 | type: string 14 | default: '' 15 | java-version: 16 | description: 'The version of Java to use for building' 17 | required: false 18 | type: string 19 | default: '11' 20 | 21 | jobs: 22 | Release: 23 | uses: netty-contrib/.github/.github/workflows/release.yml@main 24 | with: 25 | version: ${{ inputs.version }} 26 | netty: ${{ inputs.netty }} 27 | java-version: ${{ inputs.java-version }} 28 | secrets: inherit 29 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksRequestType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | /** 19 | * Type of socks request 20 | */ 21 | public enum SocksRequestType { 22 | INIT, 23 | AUTH, 24 | CMD, 25 | UNKNOWN 26 | } 27 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksResponseType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | /** 19 | * Type of socks response 20 | */ 21 | public enum SocksResponseType { 22 | INIT, 23 | AUTH, 24 | CMD, 25 | UNKNOWN 26 | } 27 | -------------------------------------------------------------------------------- /handler-proxy/src/main/java/io/netty/contrib/handler/proxy/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | /** 17 | * Adds support for client connections via proxy protocols such as 18 | * SOCKS and 19 | * HTTP CONNECT tunneling 20 | */ 21 | package io.netty.contrib.handler.proxy; 22 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/Socks4Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty.contrib.handler.codec.socksx.SocksMessage; 19 | 20 | /** 21 | * A tag interface that all SOCKS4a protocol messages implement. 22 | */ 23 | public interface Socks4Message extends SocksMessage { 24 | // Tag interface 25 | } 26 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty.contrib.handler.codec.socksx.SocksMessage; 19 | 20 | /** 21 | * A tag interface that all SOCKS5 protocol messages implement. 22 | */ 23 | public interface Socks5Message extends SocksMessage { 24 | // Tag interface 25 | } 26 | -------------------------------------------------------------------------------- /examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.netty.contrib 7 | netty-socks-proxy-parent 8 | 5.0.0.Alpha3-SNAPSHOT 9 | 10 | 11 | netty-socks-proxy-examples 12 | 5.0.0.Alpha3-SNAPSHOT 13 | 14 | 15 | 16 | io.netty.contrib 17 | netty-codec-socks 18 | ${project.version} 19 | 20 | 21 | io.netty 22 | netty5-handler 23 | ${netty.version} 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/SocksMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx; 17 | 18 | import io.netty5.handler.codec.DecoderResultProvider; 19 | 20 | /** 21 | * An interface that all SOCKS protocol messages implement. 22 | */ 23 | public interface SocksMessage extends DecoderResultProvider { 24 | 25 | /** 26 | * Returns the protocol version of this message. 27 | */ 28 | SocksVersion version(); 29 | } 30 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socks/SocksAuthResponseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertThrows; 21 | 22 | public class SocksAuthResponseTest { 23 | @Test 24 | public void testConstructorParamsAreNotNull() { 25 | assertThrows(NullPointerException.class, () -> new SocksAuthResponse(null)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socks/SocksInitRequestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertThrows; 21 | 22 | public class SocksInitRequestTest { 23 | @Test 24 | public void testConstructorParamsAreNotNull() { 25 | assertThrows(NullPointerException.class, () -> new SocksInitRequest(null)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socks/SocksInitResponseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertThrows; 21 | 22 | public class SocksInitResponseTest { 23 | @Test 24 | public void testConstructorParamsAreNotNull() { 25 | assertThrows(NullPointerException.class, () -> new SocksInitResponse(null)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5InitialRequestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertThrows; 21 | 22 | public class DefaultSocks5InitialRequestTest { 23 | @Test 24 | public void testConstructorParamsAreNotEmpty() { 25 | assertThrows(IllegalArgumentException.class, () -> new DefaultSocks5InitialRequest()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5InitialResponseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertThrows; 21 | 22 | public class DefaultSocks5InitialResponseTest { 23 | @Test 24 | public void testConstructorParamsAreNotNull() { 25 | assertThrows(NullPointerException.class, () -> new DefaultSocks5InitialResponse(null)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5PasswordAuthResponseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertThrows; 21 | 22 | public class DefaultSocks5PasswordAuthResponseTest { 23 | @Test 24 | public void testConstructorParamsAreNotNull() { 25 | assertThrows(NullPointerException.class, () -> new DefaultSocks5PasswordAuthResponse(null)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5InitialResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | /** 19 | * An initial SOCKS5 authentication method selection request, as defined in 20 | * the section 3, RFC1928. 21 | */ 22 | public interface Socks5InitialResponse extends Socks5Message { 23 | 24 | /** 25 | * Returns the {@code METHOD} field of this response. 26 | */ 27 | Socks5AuthMethod authMethod(); 28 | } 29 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5PasswordAuthResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | /** 19 | * A SOCKS5 subnegotiation response for username-password authentication, as defined in 20 | * the section 2, RFC1929. 21 | */ 22 | public interface Socks5PasswordAuthResponse extends Socks5Message { 23 | /** 24 | * Returns the status of this response. 25 | */ 26 | Socks5PasswordAuthStatus status(); 27 | } 28 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/AbstractSocks4Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty.contrib.handler.codec.socksx.AbstractSocksMessage; 19 | import io.netty.contrib.handler.codec.socksx.SocksVersion; 20 | 21 | /** 22 | * An abstract {@link Socks4Message}. 23 | */ 24 | public abstract class AbstractSocks4Message extends AbstractSocksMessage implements Socks4Message { 25 | @Override 26 | public final SocksVersion version() { 27 | return SocksVersion.SOCKS4a; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/AbstractSocks5Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty.contrib.handler.codec.socksx.AbstractSocksMessage; 19 | import io.netty.contrib.handler.codec.socksx.SocksVersion; 20 | 21 | /** 22 | * An abstract {@link Socks5Message}. 23 | */ 24 | public abstract class AbstractSocks5Message extends AbstractSocksMessage implements Socks5Message { 25 | @Override 26 | public final SocksVersion version() { 27 | return SocksVersion.SOCKS5; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5InitialRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * An initial SOCKS5 authentication method selection request, as defined in 22 | * the section 3, RFC1928. 23 | */ 24 | public interface Socks5InitialRequest extends Socks5Message { 25 | /** 26 | * Returns the list of desired authentication methods. 27 | */ 28 | List authMethods(); 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/ci-build.yml: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------------------------------- 2 | # Copyright 2021 The Netty Project 3 | # 4 | # The Netty Project licenses this file to you under the Apache License, 5 | # version 2.0 (the "License"); you may not use this file except in compliance 6 | # with the License. You may obtain a copy of the License at: 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | # ---------------------------------------------------------------------------- 16 | name: Build 17 | 18 | on: 19 | push: 20 | branches: ["main"] 21 | pull_request: 22 | branches: ["main"] 23 | workflow_dispatch: # Allows you to run this workflow manually from the Actions tab 24 | schedule: 25 | - cron: '30 8 * * 1' # At 08:30 on Monday, every Monday. 26 | 27 | jobs: 28 | Build: 29 | uses: netty-contrib/.github/.github/workflows/ci-build.yml@main 30 | secrets: inherit 31 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/NativeImageHandlerMetadataTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec; 17 | 18 | import io.netty5.nativeimage.ChannelHandlerMetadataUtil; 19 | import org.junit.jupiter.api.Test; 20 | 21 | public class NativeImageHandlerMetadataTest { 22 | 23 | @Test 24 | public void collectAndCompareMetadata() { 25 | ChannelHandlerMetadataUtil.generateMetadata( 26 | "io.netty.contrib/netty-codec-socks/reflect-config.json", 27 | "io.netty.contrib.handler.codec"); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /handler-proxy/src/test/java/io/netty/contrib/handler/proxy/NativeImageHandlerMetadataTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.proxy; 17 | 18 | import io.netty5.nativeimage.ChannelHandlerMetadataUtil; 19 | import org.junit.jupiter.api.Test; 20 | 21 | public class NativeImageHandlerMetadataTest { 22 | 23 | @Test 24 | public void collectAndCompareMetadata() { 25 | ChannelHandlerMetadataUtil.generateMetadata( 26 | "io.netty.contrib/netty-handler-proxy/reflect-config.json", 27 | "io.netty.contrib.handler.proxy"); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/Socks4CommandResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | /** 19 | * A SOCKS4a response. 20 | */ 21 | public interface Socks4CommandResponse extends Socks4Message { 22 | 23 | /** 24 | * Returns the status of this response. 25 | */ 26 | Socks4CommandStatus status(); 27 | 28 | /** 29 | * Returns the {@code DSTIP} field of this response. 30 | */ 31 | String dstAddr(); 32 | 33 | /** 34 | * Returns the {@code DSTPORT} field of this response. 35 | */ 36 | int dstPort(); 37 | } 38 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/UnknownSocksRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | 20 | /** 21 | * An unknown socks request. 22 | * 23 | * @see SocksInitRequestDecoder 24 | * @see SocksAuthRequestDecoder 25 | * @see SocksCmdRequestDecoder 26 | */ 27 | public final class UnknownSocksRequest extends SocksRequest { 28 | 29 | public UnknownSocksRequest() { 30 | super(SocksRequestType.UNKNOWN); 31 | } 32 | 33 | @Override 34 | public void encodeAsBuffer(Buffer buffer) { 35 | // NOOP 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/UnknownSocksResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | 20 | /** 21 | * An unknown socks response. 22 | * 23 | * @see SocksInitResponseDecoder 24 | * @see SocksAuthResponseDecoder 25 | * @see SocksCmdResponseDecoder 26 | */ 27 | public final class UnknownSocksResponse extends SocksResponse { 28 | 29 | public UnknownSocksResponse() { 30 | super(SocksResponseType.UNKNOWN); 31 | } 32 | 33 | @Override 34 | public void encodeAsBuffer(Buffer buffer) { 35 | // NOOP 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5PasswordAuthRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | /** 19 | * A SOCKS5 subnegotiation request for username-password authentication, as defined in 20 | * the section 2, RFC1929. 21 | */ 22 | public interface Socks5PasswordAuthRequest extends Socks5Message { 23 | 24 | /** 25 | * Returns the username of this request. 26 | */ 27 | String username(); 28 | 29 | /** 30 | * Returns the password of this request. 31 | */ 32 | String password(); 33 | } 34 | -------------------------------------------------------------------------------- /handler-proxy/src/main/resources/META-INF/native-image/io.netty.contrib/netty-handler-proxy/generated/handlers/reflect-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "io.netty.contrib.handler.proxy.HttpProxyHandler", 4 | "condition": { 5 | "typeReachable": "io.netty.contrib.handler.proxy.HttpProxyHandler" 6 | }, 7 | "queryAllPublicMethods": true 8 | }, 9 | { 10 | "name": "io.netty.contrib.handler.proxy.HttpProxyHandler$HttpClientCodecWrapper", 11 | "condition": { 12 | "typeReachable": "io.netty.contrib.handler.proxy.HttpProxyHandler$HttpClientCodecWrapper" 13 | }, 14 | "queryAllPublicMethods": true 15 | }, 16 | { 17 | "name": "io.netty.contrib.handler.proxy.ProxyHandler", 18 | "condition": { 19 | "typeReachable": "io.netty.contrib.handler.proxy.ProxyHandler" 20 | }, 21 | "queryAllPublicMethods": true 22 | }, 23 | { 24 | "name": "io.netty.contrib.handler.proxy.Socks4ProxyHandler", 25 | "condition": { 26 | "typeReachable": "io.netty.contrib.handler.proxy.Socks4ProxyHandler" 27 | }, 28 | "queryAllPublicMethods": true 29 | }, 30 | { 31 | "name": "io.netty.contrib.handler.proxy.Socks5ProxyHandler", 32 | "condition": { 33 | "typeReachable": "io.netty.contrib.handler.proxy.Socks5ProxyHandler" 34 | }, 35 | "queryAllPublicMethods": true 36 | } 37 | ] -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksAuthStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | public enum SocksAuthStatus { 19 | SUCCESS((byte) 0x00), 20 | FAILURE((byte) 0xff); 21 | 22 | private final byte b; 23 | 24 | SocksAuthStatus(byte b) { 25 | this.b = b; 26 | } 27 | 28 | public static SocksAuthStatus valueOf(byte b) { 29 | for (SocksAuthStatus code : values()) { 30 | if (code.b == b) { 31 | return code; 32 | } 33 | } 34 | return FAILURE; 35 | } 36 | 37 | public byte byteValue() { 38 | return b; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/src/main/java/io/netty/contrib/handler/codec/example/socksproxy/SocksServerUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.example.socksproxy; 17 | 18 | import io.netty5.channel.Channel; 19 | import io.netty5.channel.ChannelFutureListeners; 20 | 21 | public final class SocksServerUtils { 22 | 23 | /** 24 | * Closes the specified channel after all queued write requests are flushed. 25 | */ 26 | public static void closeOnFlush(Channel ch) { 27 | if (ch.isActive()) { 28 | ch.writeAndFlush(ch.bufferAllocator().allocate(0)).addListener(ch, ChannelFutureListeners.CLOSE); 29 | } 30 | } 31 | 32 | private SocksServerUtils() { } 33 | } 34 | -------------------------------------------------------------------------------- /handler-proxy/src/main/java/io/netty/contrib/handler/proxy/ProxyConnectException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.proxy; 17 | 18 | import java.net.ConnectException; 19 | 20 | public class ProxyConnectException extends ConnectException { 21 | private static final long serialVersionUID = 5211364632246265538L; 22 | 23 | public ProxyConnectException() { } 24 | 25 | public ProxyConnectException(String msg) { 26 | super(msg); 27 | } 28 | 29 | public ProxyConnectException(Throwable cause) { 30 | initCause(cause); 31 | } 32 | 33 | public ProxyConnectException(String msg, Throwable cause) { 34 | super(msg); 35 | initCause(cause); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksCmdType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | public enum SocksCmdType { 19 | CONNECT((byte) 0x01), 20 | BIND((byte) 0x02), 21 | UDP((byte) 0x03), 22 | UNKNOWN((byte) 0xff); 23 | 24 | private final byte b; 25 | 26 | SocksCmdType(byte b) { 27 | this.b = b; 28 | } 29 | 30 | public static SocksCmdType valueOf(byte b) { 31 | for (SocksCmdType code : values()) { 32 | if (code.b == b) { 33 | return code; 34 | } 35 | } 36 | return UNKNOWN; 37 | } 38 | 39 | public byte byteValue() { 40 | return b; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /handler-proxy/src/test/java/io/netty/contrib/handler/proxy/UnresponsiveHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.proxy; 17 | 18 | import io.netty5.channel.ChannelHandlerContext; 19 | import io.netty5.channel.SimpleChannelInboundHandler; 20 | 21 | final class UnresponsiveHandler extends SimpleChannelInboundHandler { 22 | 23 | static final UnresponsiveHandler INSTANCE = new UnresponsiveHandler(); 24 | 25 | private UnresponsiveHandler() { } 26 | 27 | @Override 28 | protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { 29 | // Ignore 30 | } 31 | 32 | @Override 33 | public boolean isSharable() { 34 | return true; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksProtocolVersion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | public enum SocksProtocolVersion { 19 | SOCKS4a((byte) 0x04), 20 | SOCKS5((byte) 0x05), 21 | UNKNOWN((byte) 0xff); 22 | 23 | private final byte b; 24 | 25 | SocksProtocolVersion(byte b) { 26 | this.b = b; 27 | } 28 | 29 | public static SocksProtocolVersion valueOf(byte b) { 30 | for (SocksProtocolVersion code : values()) { 31 | if (code.b == b) { 32 | return code; 33 | } 34 | } 35 | return UNKNOWN; 36 | } 37 | 38 | public byte byteValue() { 39 | return b; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksSubnegotiationVersion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | public enum SocksSubnegotiationVersion { 19 | AUTH_PASSWORD((byte) 0x01), 20 | UNKNOWN((byte) 0xff); 21 | 22 | private final byte b; 23 | 24 | SocksSubnegotiationVersion(byte b) { 25 | this.b = b; 26 | } 27 | 28 | public static SocksSubnegotiationVersion valueOf(byte b) { 29 | for (SocksSubnegotiationVersion code : values()) { 30 | if (code.b == b) { 31 | return code; 32 | } 33 | } 34 | return UNKNOWN; 35 | } 36 | 37 | public byte byteValue() { 38 | return b; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksAddressType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | public enum SocksAddressType { 19 | IPv4((byte) 0x01), 20 | DOMAIN((byte) 0x03), 21 | IPv6((byte) 0x04), 22 | UNKNOWN((byte) 0xff); 23 | 24 | private final byte b; 25 | 26 | SocksAddressType(byte b) { 27 | this.b = b; 28 | } 29 | 30 | public static SocksAddressType valueOf(byte b) { 31 | for (SocksAddressType code : values()) { 32 | if (code.b == b) { 33 | return code; 34 | } 35 | } 36 | return UNKNOWN; 37 | } 38 | 39 | public byte byteValue() { 40 | return b; 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socks/SocksCommonTestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.embedded.EmbeddedChannel; 20 | 21 | final class SocksCommonTestUtils { 22 | /** 23 | * A constructor to stop this class being constructed. 24 | */ 25 | private SocksCommonTestUtils() { 26 | //NOOP 27 | } 28 | 29 | @SuppressWarnings("deprecation") 30 | public static void writeMessageIntoEmbedder(EmbeddedChannel embedder, SocksMessage msg) { 31 | Buffer buf = embedder.bufferAllocator().allocate(64); 32 | msg.encodeAsBuffer(buf); 33 | embedder.writeInbound(buf); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksAuthScheme.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | public enum SocksAuthScheme { 19 | NO_AUTH((byte) 0x00), 20 | AUTH_GSSAPI((byte) 0x01), 21 | AUTH_PASSWORD((byte) 0x02), 22 | UNKNOWN((byte) 0xff); 23 | 24 | private final byte b; 25 | 26 | SocksAuthScheme(byte b) { 27 | this.b = b; 28 | } 29 | 30 | public static SocksAuthScheme valueOf(byte b) { 31 | for (SocksAuthScheme code : values()) { 32 | if (code.b == b) { 33 | return code; 34 | } 35 | } 36 | return UNKNOWN; 37 | } 38 | 39 | public byte byteValue() { 40 | return b; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/Socks4CommandRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | /** 19 | * A SOCKS4a {@code CONNECT} or {@code BIND} request. 20 | */ 21 | public interface Socks4CommandRequest extends Socks4Message { 22 | 23 | /** 24 | * Returns the type of this request. 25 | */ 26 | Socks4CommandType type(); 27 | 28 | /** 29 | * Returns the {@code USERID} field of this request. 30 | */ 31 | String userId(); 32 | 33 | /** 34 | * Returns the {@code DSTIP} field of this request. 35 | */ 36 | String dstAddr(); 37 | 38 | /** 39 | * Returns the {@code DSTPORT} field of this request. 40 | */ 41 | int dstPort(); 42 | } 43 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | 2 | The Netty Project 3 | ================= 4 | 5 | Please visit the Netty web site for more information: 6 | 7 | * https://netty.io/ 8 | 9 | Copyright 2021 The Netty Project 10 | 11 | The Netty Project licenses this file to you under the Apache License, 12 | version 2.0 (the "License"); you may not use this file except in compliance 13 | with the License. You may obtain a copy of the License at: 14 | 15 | https://www.apache.org/licenses/LICENSE-2.0 16 | 17 | Unless required by applicable law or agreed to in writing, software 18 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 19 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 20 | License for the specific language governing permissions and limitations 21 | under the License. 22 | 23 | Also, please refer to each LICENSE..txt file, which is located in 24 | the 'license' directory of the distribution file, for the license terms of the 25 | components that this product depends on. 26 | 27 | ------------------------------------------------------------------------------- 28 | 29 | This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build. 30 | 31 | * LICENSE: 32 | * license/LICENSE.mvn-wrapper.txt (Apache License 2.0) 33 | * HOMEPAGE: 34 | * https://github.com/takari/maven-wrapper 35 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/AbstractSocksMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx; 17 | 18 | import io.netty5.handler.codec.DecoderResult; 19 | 20 | import static java.util.Objects.requireNonNull; 21 | 22 | /** 23 | * An abstract {@link SocksMessage}. 24 | */ 25 | public abstract class AbstractSocksMessage implements SocksMessage { 26 | 27 | private DecoderResult decoderResult = DecoderResult.success(); 28 | 29 | @Override 30 | public DecoderResult decoderResult() { 31 | return decoderResult; 32 | } 33 | 34 | @Override 35 | public void setDecoderResult(DecoderResult decoderResult) { 36 | requireNonNull(decoderResult, "decoderResult"); 37 | this.decoderResult = decoderResult; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/src/main/java/io/netty/contrib/handler/codec/example/socksproxy/SocksServerInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.example.socksproxy; 17 | 18 | import io.netty5.channel.ChannelInitializer; 19 | import io.netty5.channel.socket.SocketChannel; 20 | import io.netty.contrib.handler.codec.socksx.SocksPortUnificationServerHandler; 21 | import io.netty5.handler.logging.LogLevel; 22 | import io.netty5.handler.logging.LoggingHandler; 23 | 24 | public final class SocksServerInitializer extends ChannelInitializer { 25 | @Override 26 | public void initChannel(SocketChannel ch) throws Exception { 27 | ch.pipeline().addLast( 28 | new LoggingHandler(LogLevel.DEBUG), 29 | new SocksPortUnificationServerHandler(), 30 | SocksServerHandler.INSTANCE); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5CommandRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | /** 19 | * A SOCKS5 request detail message, as defined in 20 | * the section 4, RFC1928. 21 | */ 22 | public interface Socks5CommandRequest extends Socks5Message { 23 | 24 | /** 25 | * Returns the type of this request. 26 | */ 27 | Socks5CommandType type(); 28 | 29 | /** 30 | * Returns the type of the {@code DST.ADDR} field of this request. 31 | */ 32 | Socks5AddressType dstAddrType(); 33 | 34 | /** 35 | * Returns the {@code DST.ADDR} field of this request. 36 | */ 37 | String dstAddr(); 38 | 39 | /** 40 | * Returns the {@code DST.PORT} field of this request. 41 | */ 42 | int dstPort(); 43 | } 44 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5CommandResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | /** 19 | * A response to a SOCKS5 request detail message, as defined in 20 | * the section 6, RFC1928. 21 | */ 22 | public interface Socks5CommandResponse extends Socks5Message { 23 | 24 | /** 25 | * Returns the status of this response. 26 | */ 27 | Socks5CommandStatus status(); 28 | 29 | /** 30 | * Returns the address type of the {@code BND.ADDR} field of this response. 31 | */ 32 | Socks5AddressType bndAddrType(); 33 | 34 | /** 35 | * Returns the {@code BND.ADDR} field of this response. 36 | */ 37 | String bndAddr(); 38 | 39 | /** 40 | * Returns the {@code BND.PORT} field of this response. 41 | */ 42 | int bndPort(); 43 | } 44 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v4/Socks4CommonTestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty5.channel.embedded.EmbeddedChannel; 19 | 20 | final class Socks4CommonTestUtils { 21 | /** 22 | * A constructor to stop this class being constructed. 23 | */ 24 | private Socks4CommonTestUtils() { 25 | //NOOP 26 | } 27 | 28 | public static void writeMessageIntoEmbedder(EmbeddedChannel embedder, Socks4Message msg) { 29 | EmbeddedChannel out; 30 | if (msg instanceof Socks4CommandRequest) { 31 | out = new EmbeddedChannel(Socks4ClientEncoder.INSTANCE); 32 | } else { 33 | out = new EmbeddedChannel(Socks4ServerEncoder.INSTANCE); 34 | } 35 | out.writeOutbound(msg); 36 | embedder.writeInbound((Object) out.readOutbound()); 37 | out.finish(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/src/main/java/io/netty/contrib/handler/codec/example/socksproxy/DirectClientHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.example.socksproxy; 17 | 18 | import io.netty5.channel.Channel; 19 | import io.netty5.channel.ChannelHandler; 20 | import io.netty5.channel.ChannelHandlerContext; 21 | import io.netty5.util.concurrent.Promise; 22 | 23 | public final class DirectClientHandler implements ChannelHandler { 24 | 25 | private final Promise promise; 26 | 27 | public DirectClientHandler(Promise promise) { 28 | this.promise = promise; 29 | } 30 | 31 | @Override 32 | public void channelActive(ChannelHandlerContext ctx) { 33 | ctx.pipeline().remove(this); 34 | promise.setSuccess(ctx.channel()); 35 | } 36 | 37 | @Override 38 | public void channelExceptionCaught(ChannelHandlerContext ctx, Throwable throwable) { 39 | promise.setFailure(throwable); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksCmdStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | public enum SocksCmdStatus { 19 | SUCCESS((byte) 0x00), 20 | FAILURE((byte) 0x01), 21 | FORBIDDEN((byte) 0x02), 22 | NETWORK_UNREACHABLE((byte) 0x03), 23 | HOST_UNREACHABLE((byte) 0x04), 24 | REFUSED((byte) 0x05), 25 | TTL_EXPIRED((byte) 0x06), 26 | COMMAND_NOT_SUPPORTED((byte) 0x07), 27 | ADDRESS_NOT_SUPPORTED((byte) 0x08), 28 | UNASSIGNED((byte) 0xff); 29 | 30 | private final byte b; 31 | 32 | SocksCmdStatus(byte b) { 33 | this.b = b; 34 | } 35 | 36 | public static SocksCmdStatus valueOf(byte b) { 37 | for (SocksCmdStatus code : values()) { 38 | if (code.b == b) { 39 | return code; 40 | } 41 | } 42 | return UNASSIGNED; 43 | } 44 | 45 | public byte byteValue() { 46 | return b; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | /** 21 | * An abstract class that defines a SocksRequest, providing common properties for 22 | * {@link SocksInitRequest}, {@link SocksAuthRequest}, {@link SocksCmdRequest} and {@link UnknownSocksRequest}. 23 | * 24 | * @see SocksInitRequest 25 | * @see SocksAuthRequest 26 | * @see SocksCmdRequest 27 | * @see UnknownSocksRequest 28 | */ 29 | public abstract class SocksRequest extends SocksMessage { 30 | private final SocksRequestType requestType; 31 | 32 | protected SocksRequest(SocksRequestType requestType) { 33 | super(SocksMessageType.REQUEST); 34 | requireNonNull(requestType, "requestType"); 35 | this.requestType = requestType; 36 | } 37 | 38 | /** 39 | * Returns socks request type 40 | * 41 | * @return socks request type 42 | */ 43 | public SocksRequestType requestType() { 44 | return requestType; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v5/Socks5PasswordAuthRequestDecoderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.channel.embedded.EmbeddedChannel; 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.junit.jupiter.api.Assertions.assertNull; 23 | 24 | public class Socks5PasswordAuthRequestDecoderTest { 25 | 26 | @Test 27 | public void testAuthRequestDecoder() { 28 | String username = "testUsername"; 29 | String password = "testPassword"; 30 | Socks5PasswordAuthRequest msg = new DefaultSocks5PasswordAuthRequest(username, password); 31 | EmbeddedChannel embedder = new EmbeddedChannel(new Socks5PasswordAuthRequestDecoder()); 32 | Socks5CommonTestUtils.writeFromClientToServer(embedder, msg); 33 | msg = embedder.readInbound(); 34 | assertEquals(username, msg.username()); 35 | assertEquals(password, msg.password()); 36 | assertNull(embedder.readInbound()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | /** 21 | * An abstract class that defines a SocksResponse, providing common properties for 22 | * {@link SocksInitResponse}, {@link SocksAuthResponse}, {@link SocksCmdResponse} and {@link UnknownSocksResponse}. 23 | * 24 | * @see SocksInitResponse 25 | * @see SocksAuthResponse 26 | * @see SocksCmdResponse 27 | * @see UnknownSocksResponse 28 | */ 29 | public abstract class SocksResponse extends SocksMessage { 30 | private final SocksResponseType responseType; 31 | 32 | protected SocksResponse(SocksResponseType responseType) { 33 | super(SocksMessageType.RESPONSE); 34 | requireNonNull(responseType, "responseType"); 35 | this.responseType = responseType; 36 | } 37 | 38 | /** 39 | * Returns socks response type 40 | * 41 | * @return socks response type 42 | */ 43 | public SocksResponseType responseType() { 44 | return responseType; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksMessageEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.MessageToByteEncoder; 21 | 22 | /** 23 | * Encodes an {@link SocksMessage} into a {@link Buffer}. 24 | * {@link MessageToByteEncoder} implementation. 25 | * Use this with {@link SocksInitRequest}, {@link SocksInitResponse}, {@link SocksAuthRequest}, 26 | * {@link SocksAuthResponse}, {@link SocksCmdRequest} and {@link SocksCmdResponse} 27 | */ 28 | public class SocksMessageEncoder extends MessageToByteEncoder { 29 | 30 | @Override 31 | protected Buffer allocateBuffer(ChannelHandlerContext ctx, SocksMessage msg) { 32 | return ctx.bufferAllocator().allocate(256); 33 | } 34 | 35 | @Override 36 | @SuppressWarnings("deprecation") 37 | protected void encode(ChannelHandlerContext ctx, SocksMessage msg, Buffer out) { 38 | msg.encodeAsBuffer(out); 39 | } 40 | 41 | @Override 42 | public boolean isSharable() { 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksInitResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | 20 | import static java.util.Objects.requireNonNull; 21 | 22 | /** 23 | * An socks init response. 24 | * 25 | * @see SocksInitRequest 26 | * @see SocksInitResponseDecoder 27 | */ 28 | public final class SocksInitResponse extends SocksResponse { 29 | private final SocksAuthScheme authScheme; 30 | 31 | public SocksInitResponse(SocksAuthScheme authScheme) { 32 | super(SocksResponseType.INIT); 33 | requireNonNull(authScheme, "authScheme"); 34 | this.authScheme = authScheme; 35 | } 36 | 37 | /** 38 | * Returns the {@link SocksAuthScheme} of this {@link SocksInitResponse} 39 | * 40 | * @return The {@link SocksAuthScheme} of this {@link SocksInitResponse} 41 | */ 42 | public SocksAuthScheme authScheme() { 43 | return authScheme; 44 | } 45 | 46 | @Override 47 | public void encodeAsBuffer(Buffer buffer) { 48 | buffer.writeByte(protocolVersion().byteValue()); 49 | buffer.writeByte(authScheme.byteValue()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v5/Socks5InitialRequestDecoderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.channel.embedded.EmbeddedChannel; 19 | import io.netty5.handler.codec.DecoderResult; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertFalse; 23 | import static org.junit.jupiter.api.Assertions.assertSame; 24 | import static org.junit.jupiter.api.Assertions.assertTrue; 25 | 26 | public class Socks5InitialRequestDecoderTest { 27 | @Test 28 | public void testUnpackingCausesDecodeFail() { 29 | EmbeddedChannel e = new EmbeddedChannel(new Socks5InitialRequestDecoder()); 30 | assertFalse(e.writeInbound(e.bufferAllocator().copyOf(new byte[]{5, 2, 0}))); 31 | assertTrue(e.writeInbound(e.bufferAllocator().copyOf(new byte[]{1}))); 32 | Object o = e.readInbound(); 33 | 34 | assertTrue(o instanceof DefaultSocks5InitialRequest); 35 | DefaultSocks5InitialRequest req = (DefaultSocks5InitialRequest) o; 36 | assertSame(req.decoderResult(), DecoderResult.success()); 37 | assertFalse(e.finish()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksAuthResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | 20 | import static java.util.Objects.requireNonNull; 21 | 22 | /** 23 | * An socks auth response. 24 | * 25 | * @see SocksAuthRequest 26 | * @see SocksAuthResponseDecoder 27 | */ 28 | public final class SocksAuthResponse extends SocksResponse { 29 | private static final SocksSubnegotiationVersion SUBNEGOTIATION_VERSION = SocksSubnegotiationVersion.AUTH_PASSWORD; 30 | private final SocksAuthStatus authStatus; 31 | 32 | public SocksAuthResponse(SocksAuthStatus authStatus) { 33 | super(SocksResponseType.AUTH); 34 | requireNonNull(authStatus, "authStatus"); 35 | this.authStatus = authStatus; 36 | } 37 | 38 | /** 39 | * Returns the {@link SocksAuthStatus} of this {@link SocksAuthResponse} 40 | * 41 | * @return The {@link SocksAuthStatus} of this {@link SocksAuthResponse} 42 | */ 43 | public SocksAuthStatus authStatus() { 44 | return authStatus; 45 | } 46 | 47 | @Override 48 | public void encodeAsBuffer(Buffer buffer) { 49 | buffer.writeByte(SUBNEGOTIATION_VERSION.byteValue()); 50 | buffer.writeByte(authStatus.byteValue()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/SocksVersion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx; 17 | 18 | /** 19 | * The version of SOCKS protocol. 20 | */ 21 | public enum SocksVersion { 22 | /** 23 | * SOCKS protocol version 4a (or 4) 24 | */ 25 | SOCKS4a((byte) 0x04), 26 | /** 27 | * SOCKS protocol version 5 28 | */ 29 | SOCKS5((byte) 0x05), 30 | /** 31 | * Unknown protocol version 32 | */ 33 | UNKNOWN((byte) 0xff); 34 | 35 | /** 36 | * Returns the {@link SocksVersion} that corresponds to the specified version field value, 37 | * as defined in the protocol specification. 38 | * 39 | * @return {@link #UNKNOWN} if the specified value does not represent a known SOCKS protocol version 40 | */ 41 | public static SocksVersion valueOf(byte b) { 42 | if (b == SOCKS4a.byteValue()) { 43 | return SOCKS4a; 44 | } 45 | if (b == SOCKS5.byteValue()) { 46 | return SOCKS5; 47 | } 48 | return UNKNOWN; 49 | } 50 | 51 | private final byte b; 52 | 53 | SocksVersion(byte b) { 54 | this.b = b; 55 | } 56 | 57 | /** 58 | * Returns the value of the version field, as defined in the protocol specification. 59 | */ 60 | public byte byteValue() { 61 | return b; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v5/Socks5CommonTestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.embedded.EmbeddedChannel; 20 | 21 | final class Socks5CommonTestUtils { 22 | /** 23 | * A constructor to stop this class being constructed. 24 | */ 25 | private Socks5CommonTestUtils() { 26 | //NOOP 27 | } 28 | 29 | public static void writeFromClientToServer(EmbeddedChannel embedder, Socks5Message msg) { 30 | embedder.writeInbound(encodeClient(msg)); 31 | } 32 | 33 | public static void writeFromServerToClient(EmbeddedChannel embedder, Socks5Message msg) { 34 | embedder.writeInbound(encodeServer(msg)); 35 | } 36 | 37 | public static Buffer encodeClient(Socks5Message msg) { 38 | EmbeddedChannel out = new EmbeddedChannel(Socks5ClientEncoder.DEFAULT); 39 | out.writeOutbound(msg); 40 | 41 | Buffer encoded = out.readOutbound(); 42 | out.finish(); 43 | 44 | return encoded; 45 | } 46 | 47 | public static Buffer encodeServer(Socks5Message msg) { 48 | EmbeddedChannel out = new EmbeddedChannel(Socks5ServerEncoder.DEFAULT); 49 | out.writeOutbound(msg); 50 | 51 | Buffer encoded = out.readOutbound(); 52 | out.finish(); 53 | 54 | return encoded; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v5/Socks5PasswordAuthResponseDecoderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.channel.embedded.EmbeddedChannel; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import static org.junit.jupiter.api.Assertions.assertNull; 24 | import static org.junit.jupiter.api.Assertions.assertSame; 25 | 26 | public class Socks5PasswordAuthResponseDecoderTest { 27 | private static final Logger logger = LoggerFactory.getLogger( 28 | Socks5PasswordAuthResponseDecoderTest.class); 29 | 30 | private static void test(Socks5PasswordAuthStatus status) { 31 | logger.debug("Testing Socks5PasswordAuthResponseDecoder with status: " + status); 32 | Socks5PasswordAuthResponse msg = new DefaultSocks5PasswordAuthResponse(status); 33 | EmbeddedChannel embedder = new EmbeddedChannel(new Socks5PasswordAuthResponseDecoder()); 34 | Socks5CommonTestUtils.writeFromServerToClient(embedder, msg); 35 | msg = embedder.readInbound(); 36 | assertSame(msg.status(), status); 37 | assertNull(embedder.readInbound()); 38 | } 39 | 40 | @Test 41 | public void testSocksCmdResponseDecoder() { 42 | test(Socks5PasswordAuthStatus.SUCCESS); 43 | test(Socks5PasswordAuthStatus.FAILURE); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /examples/src/main/java/io/netty/contrib/handler/codec/example/socksproxy/RelayHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.example.socksproxy; 17 | 18 | import io.netty5.channel.Channel; 19 | import io.netty5.channel.ChannelHandler; 20 | import io.netty5.channel.ChannelHandlerContext; 21 | import io.netty5.util.ReferenceCountUtil; 22 | 23 | public final class RelayHandler implements ChannelHandler { 24 | 25 | private final Channel relayChannel; 26 | 27 | public RelayHandler(Channel relayChannel) { 28 | this.relayChannel = relayChannel; 29 | } 30 | 31 | @Override 32 | public void channelActive(ChannelHandlerContext ctx) { 33 | ctx.writeAndFlush(ctx.bufferAllocator().allocate(0)); 34 | } 35 | 36 | @Override 37 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 38 | if (relayChannel.isActive()) { 39 | relayChannel.writeAndFlush(msg); 40 | } else { 41 | ReferenceCountUtil.release(msg); 42 | } 43 | } 44 | 45 | @Override 46 | public void channelInactive(ChannelHandlerContext ctx) { 47 | if (relayChannel.isActive()) { 48 | SocksServerUtils.closeOnFlush(relayChannel); 49 | } 50 | } 51 | 52 | @Override 53 | public void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 54 | cause.printStackTrace(); 55 | ctx.close(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /examples/src/main/java/io/netty/contrib/handler/codec/example/socksproxy/SocksServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.example.socksproxy; 17 | 18 | import io.netty5.bootstrap.ServerBootstrap; 19 | import io.netty5.channel.EventLoopGroup; 20 | import io.netty5.channel.MultithreadEventLoopGroup; 21 | import io.netty5.channel.nio.NioHandler; 22 | import io.netty5.channel.socket.nio.NioServerSocketChannel; 23 | import io.netty5.handler.logging.LogLevel; 24 | import io.netty5.handler.logging.LoggingHandler; 25 | 26 | public final class SocksServer { 27 | 28 | static final int PORT = Integer.parseInt(System.getProperty("port", "1080")); 29 | 30 | public static void main(String[] args) throws Exception { 31 | EventLoopGroup bossGroup = new MultithreadEventLoopGroup(1, NioHandler.newFactory()); 32 | EventLoopGroup workerGroup = new MultithreadEventLoopGroup(NioHandler.newFactory()); 33 | try { 34 | ServerBootstrap b = new ServerBootstrap(); 35 | b.group(bossGroup, workerGroup) 36 | .channel(NioServerSocketChannel.class) 37 | .handler(new LoggingHandler(LogLevel.INFO)) 38 | .childHandler(new SocksServerInitializer()); 39 | b.bind(PORT).asStage().get().closeFuture().asStage().sync(); 40 | } finally { 41 | bossGroup.shutdownGracefully(); 42 | workerGroup.shutdownGracefully(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5InitialResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.handler.codec.DecoderResult; 19 | import io.netty5.util.internal.StringUtil; 20 | 21 | import static java.util.Objects.requireNonNull; 22 | 23 | /** 24 | * The default {@link Socks5InitialResponse}. 25 | */ 26 | public class DefaultSocks5InitialResponse extends AbstractSocks5Message implements Socks5InitialResponse { 27 | 28 | private final Socks5AuthMethod authMethod; 29 | 30 | public DefaultSocks5InitialResponse(Socks5AuthMethod authMethod) { 31 | requireNonNull(authMethod, "authMethod"); 32 | this.authMethod = authMethod; 33 | } 34 | 35 | @Override 36 | public Socks5AuthMethod authMethod() { 37 | return authMethod; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | StringBuilder buf = new StringBuilder(StringUtil.simpleClassName(this)); 43 | 44 | DecoderResult decoderResult = decoderResult(); 45 | if (!decoderResult.isSuccess()) { 46 | buf.append("(decoderResult: "); 47 | buf.append(decoderResult); 48 | buf.append(", authMethod: "); 49 | } else { 50 | buf.append("(authMethod: "); 51 | } 52 | buf.append(authMethod()); 53 | buf.append(')'); 54 | 55 | return buf.toString(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5PasswordAuthResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.handler.codec.DecoderResult; 19 | import io.netty5.util.internal.StringUtil; 20 | 21 | import static java.util.Objects.requireNonNull; 22 | 23 | /** 24 | * The default {@link Socks5PasswordAuthResponse}. 25 | */ 26 | public class DefaultSocks5PasswordAuthResponse extends AbstractSocks5Message implements Socks5PasswordAuthResponse { 27 | 28 | private final Socks5PasswordAuthStatus status; 29 | 30 | public DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus status) { 31 | requireNonNull(status, "status"); 32 | 33 | this.status = status; 34 | } 35 | 36 | @Override 37 | public Socks5PasswordAuthStatus status() { 38 | return status; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | StringBuilder buf = new StringBuilder(StringUtil.simpleClassName(this)); 44 | 45 | DecoderResult decoderResult = decoderResult(); 46 | if (!decoderResult.isSuccess()) { 47 | buf.append("(decoderResult: "); 48 | buf.append(decoderResult); 49 | buf.append(", status: "); 50 | } else { 51 | buf.append("(status: "); 52 | } 53 | buf.append(status()); 54 | buf.append(')'); 55 | 56 | return buf.toString(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksInitRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | 20 | import java.util.Collections; 21 | import java.util.List; 22 | 23 | import static java.util.Objects.requireNonNull; 24 | 25 | /** 26 | * An socks init request. 27 | * 28 | * @see SocksInitResponse 29 | * @see SocksInitRequestDecoder 30 | */ 31 | public final class SocksInitRequest extends SocksRequest { 32 | private final List authSchemes; 33 | 34 | public SocksInitRequest(List authSchemes) { 35 | super(SocksRequestType.INIT); 36 | requireNonNull(authSchemes, "authSchemes"); 37 | this.authSchemes = authSchemes; 38 | } 39 | 40 | /** 41 | * Returns the List<{@link SocksAuthScheme}> of this {@link SocksInitRequest} 42 | * 43 | * @return The List<{@link SocksAuthScheme}> of this {@link SocksInitRequest} 44 | */ 45 | public List authSchemes() { 46 | return Collections.unmodifiableList(authSchemes); 47 | } 48 | 49 | @Override 50 | public void encodeAsBuffer(Buffer buffer) { 51 | buffer.writeByte(protocolVersion().byteValue()); 52 | buffer.writeByte((byte) authSchemes.size()); 53 | for (SocksAuthScheme authScheme : authSchemes) { 54 | buffer.writeByte(authScheme.byteValue()); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksCommonUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.util.internal.StringUtil; 19 | 20 | final class SocksCommonUtils { 21 | public static final SocksRequest UNKNOWN_SOCKS_REQUEST = new UnknownSocksRequest(); 22 | public static final SocksResponse UNKNOWN_SOCKS_RESPONSE = new UnknownSocksResponse(); 23 | 24 | /** 25 | * A constructor to stop this class being constructed. 26 | */ 27 | private SocksCommonUtils() { 28 | // NOOP 29 | } 30 | 31 | private static final char ipv6hextetSeparator = ':'; 32 | 33 | /** 34 | * Converts numeric IPv6 to standard (non-compressed) format. 35 | */ 36 | public static String ipv6toStr(byte[] src) { 37 | assert src.length == 16; 38 | StringBuilder sb = new StringBuilder(39); 39 | ipv6toStr(sb, src, 0, 8); 40 | return sb.toString(); 41 | } 42 | 43 | private static void ipv6toStr(StringBuilder sb, byte[] src, int fromHextet, int toHextet) { 44 | int i; 45 | toHextet --; 46 | for (i = fromHextet; i < toHextet; i++) { 47 | appendHextet(sb, src, i); 48 | sb.append(ipv6hextetSeparator); 49 | } 50 | 51 | appendHextet(sb, src, i); 52 | } 53 | 54 | private static void appendHextet(StringBuilder sb, byte[] src, int i) { 55 | StringUtil.toHexString(sb, src, i << 1, 2); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/Socks4ServerEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.MessageToByteEncoder; 21 | import io.netty5.util.NetUtil; 22 | 23 | /** 24 | * Encodes a {@link Socks4CommandResponse} into a {@link Buffer}. 25 | */ 26 | public final class Socks4ServerEncoder extends MessageToByteEncoder { 27 | 28 | public static final Socks4ServerEncoder INSTANCE = new Socks4ServerEncoder(); 29 | 30 | private static final byte[] IPv4_HOSTNAME_ZEROED = { 0x00, 0x00, 0x00, 0x00 }; 31 | 32 | private Socks4ServerEncoder() { } 33 | 34 | @Override 35 | protected Buffer allocateBuffer(ChannelHandlerContext ctx, Socks4CommandResponse msg) { 36 | return ctx.bufferAllocator().allocate(256); 37 | } 38 | 39 | @Override 40 | protected void encode(ChannelHandlerContext ctx, Socks4CommandResponse msg, Buffer out) { 41 | out.writeByte((byte) 0); 42 | out.writeByte(msg.status().byteValue()); 43 | out.writeShort((short) msg.dstPort()); 44 | out.writeBytes(msg.dstAddr() == null? IPv4_HOSTNAME_ZEROED 45 | : NetUtil.createByteArrayFromIpAddressString(msg.dstAddr())); 46 | } 47 | 48 | @Override 49 | public boolean isSharable() { 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socks/SocksAuthResponseDecoderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.channel.embedded.EmbeddedChannel; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import static org.junit.jupiter.api.Assertions.assertNull; 24 | import static org.junit.jupiter.api.Assertions.assertSame; 25 | 26 | public class SocksAuthResponseDecoderTest { 27 | private static final Logger logger = LoggerFactory.getLogger(SocksAuthResponseDecoderTest.class); 28 | 29 | private static void testSocksAuthResponseDecoderWithDifferentParams(SocksAuthStatus authStatus) { 30 | logger.debug("Testing SocksAuthResponseDecoder with authStatus: " + authStatus); 31 | SocksAuthResponse msg = new SocksAuthResponse(authStatus); 32 | SocksAuthResponseDecoder decoder = new SocksAuthResponseDecoder(); 33 | EmbeddedChannel embedder = new EmbeddedChannel(decoder); 34 | SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); 35 | msg = embedder.readInbound(); 36 | assertSame(msg.authStatus(), authStatus); 37 | assertNull(embedder.readInbound()); 38 | } 39 | 40 | @Test 41 | public void testSocksCmdResponseDecoder() { 42 | for (SocksAuthStatus authStatus: SocksAuthStatus.values()) { 43 | testSocksAuthResponseDecoderWithDifferentParams(authStatus); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | 20 | import static java.util.Objects.requireNonNull; 21 | 22 | /** 23 | * An abstract class that defines a SocksMessage, providing common properties for 24 | * {@link SocksRequest} and {@link SocksResponse}. 25 | * 26 | * @see SocksRequest 27 | * @see SocksResponse 28 | */ 29 | public abstract class SocksMessage { 30 | private final SocksMessageType type; 31 | private final SocksProtocolVersion protocolVersion = SocksProtocolVersion.SOCKS5; 32 | 33 | protected SocksMessage(SocksMessageType type) { 34 | requireNonNull(type, "type"); 35 | this.type = type; 36 | } 37 | 38 | /** 39 | * Returns the {@link SocksMessageType} of this {@link SocksMessage} 40 | * 41 | * @return The {@link SocksMessageType} of this {@link SocksMessage} 42 | */ 43 | public SocksMessageType type() { 44 | return type; 45 | } 46 | 47 | /** 48 | * Returns the {@link SocksProtocolVersion} of this {@link SocksMessage} 49 | * 50 | * @return The {@link SocksProtocolVersion} of this {@link SocksMessage} 51 | */ 52 | public SocksProtocolVersion protocolVersion() { 53 | return protocolVersion; 54 | } 55 | 56 | /** 57 | * @deprecated Do not use; this method was intended for an internal use only. 58 | */ 59 | @Deprecated 60 | public abstract void encodeAsBuffer(Buffer buffer); 61 | } 62 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v4/Socks4ClientDecoderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty5.channel.embedded.EmbeddedChannel; 19 | import org.junit.jupiter.api.Test; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import static org.junit.jupiter.api.Assertions.assertEquals; 24 | import static org.junit.jupiter.api.Assertions.assertNull; 25 | 26 | public class Socks4ClientDecoderTest { 27 | private static final Logger logger = LoggerFactory.getLogger(Socks4ClientDecoderTest.class); 28 | 29 | private static void test(Socks4CommandStatus cmdStatus, String dstAddr, int dstPort) { 30 | logger.debug("Testing cmdStatus: " + cmdStatus); 31 | Socks4CommandResponse msg = new DefaultSocks4CommandResponse(cmdStatus, dstAddr, dstPort); 32 | EmbeddedChannel embedder = new EmbeddedChannel(new Socks4ClientDecoder()); 33 | Socks4CommonTestUtils.writeMessageIntoEmbedder(embedder, msg); 34 | 35 | msg = embedder.readInbound(); 36 | assertEquals(msg.status(), cmdStatus); 37 | if (dstAddr != null) { 38 | assertEquals(msg.dstAddr(), dstAddr); 39 | } 40 | assertEquals(msg.dstPort(), dstPort); 41 | assertNull(embedder.readInbound()); 42 | } 43 | 44 | /** 45 | * Verifies that sent socks messages are decoded correctly. 46 | */ 47 | @Test 48 | public void testSocksCmdResponseDecoder() { 49 | test(Socks4CommandStatus.IDENTD_AUTH_FAILURE, null, 0); 50 | test(Socks4CommandStatus.IDENTD_UNREACHABLE, null, 0); 51 | test(Socks4CommandStatus.REJECTED_OR_FAILED, null, 0); 52 | test(Socks4CommandStatus.SUCCESS, null, 0); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksInitResponseDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.ByteToMessageDecoder; 21 | 22 | /** 23 | * Decodes {@link Buffer}s into {@link SocksInitResponse}. 24 | * Before returning SocksResponse decoder removes itself from pipeline. 25 | */ 26 | public class SocksInitResponseDecoder extends ByteToMessageDecoder { 27 | 28 | private enum State { 29 | CHECK_PROTOCOL_VERSION, 30 | READ_PREFERRED_AUTH_TYPE 31 | } 32 | private State state = State.CHECK_PROTOCOL_VERSION; 33 | 34 | @Override 35 | protected void decode(ChannelHandlerContext ctx, Buffer buffer) throws Exception { 36 | switch (state) { 37 | case CHECK_PROTOCOL_VERSION: { 38 | if (buffer.readableBytes() < 1) { 39 | return; 40 | } 41 | if (buffer.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) { 42 | ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE); 43 | break; 44 | } 45 | state = State.READ_PREFERRED_AUTH_TYPE; 46 | } 47 | case READ_PREFERRED_AUTH_TYPE: { 48 | if (buffer.readableBytes() < 1) { 49 | return; 50 | } 51 | SocksAuthScheme authScheme = SocksAuthScheme.valueOf(buffer.readByte()); 52 | ctx.fireChannelRead(new SocksInitResponse(authScheme)); 53 | break; 54 | } 55 | default: { 56 | throw new Error(); 57 | } 58 | } 59 | ctx.pipeline().remove(this); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksAuthResponseDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.ByteToMessageDecoder; 21 | 22 | /** 23 | * Decodes {@link Buffer}s into {@link SocksAuthResponse}. 24 | * Before returning SocksResponse decoder removes itself from pipeline. 25 | */ 26 | public class SocksAuthResponseDecoder extends ByteToMessageDecoder { 27 | 28 | private enum State { 29 | CHECK_PROTOCOL_VERSION, 30 | READ_AUTH_RESPONSE 31 | } 32 | 33 | private State state = State.CHECK_PROTOCOL_VERSION; 34 | 35 | @Override 36 | protected void decode(ChannelHandlerContext ctx, Buffer buffer) 37 | throws Exception { 38 | switch (state) { 39 | case CHECK_PROTOCOL_VERSION: { 40 | if (buffer.readableBytes() < 1) { 41 | return; 42 | } 43 | if (buffer.readByte() != SocksSubnegotiationVersion.AUTH_PASSWORD.byteValue()) { 44 | ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE); 45 | break; 46 | } 47 | state = State.READ_AUTH_RESPONSE; 48 | } 49 | case READ_AUTH_RESPONSE: { 50 | if (buffer.readableBytes() < 1) { 51 | return; 52 | } 53 | SocksAuthStatus authStatus = SocksAuthStatus.valueOf(buffer.readByte()); 54 | ctx.fireChannelRead(new SocksAuthResponse(authStatus)); 55 | break; 56 | } 57 | default: { 58 | throw new Error(); 59 | } 60 | } 61 | ctx.pipeline().remove(this); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/Socks4CommandType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | /** 21 | * The type of {@link Socks4CommandRequest}. 22 | */ 23 | public class Socks4CommandType implements Comparable { 24 | 25 | public static final Socks4CommandType CONNECT = new Socks4CommandType(0x01, "CONNECT"); 26 | public static final Socks4CommandType BIND = new Socks4CommandType(0x02, "BIND"); 27 | 28 | public static Socks4CommandType valueOf(byte b) { 29 | switch (b) { 30 | case 0x01: 31 | return CONNECT; 32 | case 0x02: 33 | return BIND; 34 | } 35 | 36 | return new Socks4CommandType(b); 37 | } 38 | 39 | private final byte byteValue; 40 | private final String name; 41 | private String text; 42 | 43 | public Socks4CommandType(int byteValue) { 44 | this(byteValue, "UNKNOWN"); 45 | } 46 | 47 | public Socks4CommandType(int byteValue, String name) { 48 | requireNonNull(name, "name"); 49 | this.byteValue = (byte) byteValue; 50 | this.name = name; 51 | } 52 | 53 | public byte byteValue() { 54 | return byteValue; 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return byteValue; 60 | } 61 | 62 | @Override 63 | public boolean equals(Object obj) { 64 | if (!(obj instanceof Socks4CommandType)) { 65 | return false; 66 | } 67 | 68 | return byteValue == ((Socks4CommandType) obj).byteValue; 69 | } 70 | 71 | @Override 72 | public int compareTo(Socks4CommandType o) { 73 | return byteValue - o.byteValue; 74 | } 75 | 76 | @Override 77 | public String toString() { 78 | String text = this.text; 79 | if (text == null) { 80 | this.text = text = name + '(' + (byteValue & 0xFF) + ')'; 81 | } 82 | return text; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/Socks4ClientEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.MessageToByteEncoder; 21 | import java.nio.charset.StandardCharsets; 22 | import io.netty5.util.NetUtil; 23 | 24 | /** 25 | * Encodes a {@link Socks4CommandRequest} into a {@link Buffer}. 26 | */ 27 | public final class Socks4ClientEncoder extends MessageToByteEncoder { 28 | 29 | /** 30 | * The singleton instance of {@link Socks4ClientEncoder} 31 | */ 32 | public static final Socks4ClientEncoder INSTANCE = new Socks4ClientEncoder(); 33 | 34 | private static final byte[] IPv4_DOMAIN_MARKER = {0x00, 0x00, 0x00, 0x01}; 35 | 36 | private Socks4ClientEncoder() { } 37 | 38 | @Override 39 | protected Buffer allocateBuffer(ChannelHandlerContext ctx, Socks4CommandRequest msg) { 40 | return ctx.bufferAllocator().allocate(256); 41 | } 42 | 43 | @Override 44 | protected void encode(ChannelHandlerContext ctx, Socks4CommandRequest msg, Buffer out) { 45 | out.writeByte(msg.version().byteValue()); 46 | out.writeByte(msg.type().byteValue()); 47 | out.writeShort((short) msg.dstPort()); 48 | if (NetUtil.isValidIpV4Address(msg.dstAddr())) { 49 | out.writeBytes(NetUtil.createByteArrayFromIpAddressString(msg.dstAddr())); 50 | out.writeCharSequence(msg.userId(), StandardCharsets.US_ASCII); 51 | out.writeByte((byte) 0); 52 | } else { 53 | out.writeBytes(IPv4_DOMAIN_MARKER); 54 | out.writeCharSequence(msg.userId(), StandardCharsets.US_ASCII); 55 | out.writeByte((byte) 0); 56 | out.writeCharSequence(msg.dstAddr(), StandardCharsets.US_ASCII); 57 | out.writeByte((byte) 0); 58 | } 59 | } 60 | 61 | @Override 62 | public boolean isSharable() { 63 | return true; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5AddressEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.handler.codec.EncoderException; 20 | import java.nio.charset.StandardCharsets; 21 | import io.netty5.util.NetUtil; 22 | 23 | /** 24 | * Encodes a SOCKS5 address into binary representation. 25 | * 26 | * @see Socks5ClientEncoder 27 | * @see Socks5ServerEncoder 28 | */ 29 | public interface Socks5AddressEncoder { 30 | 31 | Socks5AddressEncoder DEFAULT = (addrType, addrValue, out) -> { 32 | final byte typeVal = addrType.byteValue(); 33 | if (typeVal == Socks5AddressType.IPv4.byteValue()) { 34 | if (addrValue != null) { 35 | out.writeBytes(NetUtil.createByteArrayFromIpAddressString(addrValue)); 36 | } else { 37 | out.writeInt(0); 38 | } 39 | } else if (typeVal == Socks5AddressType.DOMAIN.byteValue()) { 40 | if (addrValue != null) { 41 | out.writeByte((byte) addrValue.length()); 42 | out.writeCharSequence(addrValue, StandardCharsets.US_ASCII); 43 | } else { 44 | out.writeByte((byte) 0); 45 | } 46 | } else if (typeVal == Socks5AddressType.IPv6.byteValue()) { 47 | if (addrValue != null) { 48 | out.writeBytes(NetUtil.createByteArrayFromIpAddressString(addrValue)); 49 | } else { 50 | out.writeLong(0); 51 | out.writeLong(0); 52 | } 53 | } else { 54 | throw new EncoderException("unsupported addrType: " + (addrType.byteValue() & 0xFF)); 55 | } 56 | }; 57 | 58 | /** 59 | * Encodes a SOCKS5 address. 60 | * 61 | * @param addrType the type of the address 62 | * @param addrValue the string representation of the address 63 | * @param out the output buffer where the encoded SOCKS5 address field will be written to 64 | */ 65 | void encodeAddress(Socks5AddressType addrType, String addrValue, Buffer out) throws Exception; 66 | } 67 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v4/Socks4ServerDecoderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty5.channel.embedded.EmbeddedChannel; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import java.util.Arrays; 24 | 25 | import static org.junit.jupiter.api.Assertions.assertEquals; 26 | import static org.junit.jupiter.api.Assertions.assertNull; 27 | import static org.junit.jupiter.api.Assertions.assertSame; 28 | 29 | public class Socks4ServerDecoderTest { 30 | private static final Logger logger = LoggerFactory.getLogger(Socks4ServerDecoderTest.class); 31 | 32 | private static void test(String userId, Socks4CommandType type, String dstAddr, int dstPort) { 33 | logger.debug( 34 | "Testing type: " + type + " dstAddr: " + dstAddr + " dstPort: " + dstPort + 35 | " userId: " + userId); 36 | 37 | Socks4CommandRequest msg = new DefaultSocks4CommandRequest(type, dstAddr, dstPort, userId); 38 | EmbeddedChannel embedder = new EmbeddedChannel(new Socks4ServerDecoder()); 39 | Socks4CommonTestUtils.writeMessageIntoEmbedder(embedder, msg); 40 | msg = embedder.readInbound(); 41 | assertSame(msg.type(), type); 42 | assertEquals(msg.dstAddr(), dstAddr); 43 | assertEquals(msg.dstPort(), dstPort); 44 | assertEquals(msg.userId(), userId); 45 | assertNull(embedder.readInbound()); 46 | } 47 | 48 | @Test 49 | public void testCmdRequestDecoder() { 50 | String[] hosts = { "127.0.0.1", }; 51 | String[] userIds = { "test", }; 52 | int[] ports = {1, 32769, 65535}; 53 | 54 | for (Socks4CommandType cmdType : Arrays.asList(Socks4CommandType.BIND, 55 | Socks4CommandType.CONNECT)) { 56 | for (String userId : userIds) { 57 | for (String host : hosts) { 58 | for (int port : ports) { 59 | test(userId, cmdType, host, port); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5CommandType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | /** 21 | * The type of {@link Socks5CommandRequest}. 22 | */ 23 | public class Socks5CommandType implements Comparable { 24 | 25 | public static final Socks5CommandType CONNECT = new Socks5CommandType(0x01, "CONNECT"); 26 | public static final Socks5CommandType BIND = new Socks5CommandType(0x02, "BIND"); 27 | public static final Socks5CommandType UDP_ASSOCIATE = new Socks5CommandType(0x03, "UDP_ASSOCIATE"); 28 | 29 | public static Socks5CommandType valueOf(byte b) { 30 | switch (b) { 31 | case 0x01: 32 | return CONNECT; 33 | case 0x02: 34 | return BIND; 35 | case 0x03: 36 | return UDP_ASSOCIATE; 37 | } 38 | 39 | return new Socks5CommandType(b); 40 | } 41 | 42 | private final byte byteValue; 43 | private final String name; 44 | private String text; 45 | 46 | public Socks5CommandType(int byteValue) { 47 | this(byteValue, "UNKNOWN"); 48 | } 49 | 50 | public Socks5CommandType(int byteValue, String name) { 51 | requireNonNull(name, "name"); 52 | 53 | this.byteValue = (byte) byteValue; 54 | this.name = name; 55 | } 56 | 57 | public byte byteValue() { 58 | return byteValue; 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return byteValue; 64 | } 65 | 66 | @Override 67 | public boolean equals(Object obj) { 68 | if (!(obj instanceof Socks5CommandType)) { 69 | return false; 70 | } 71 | 72 | return byteValue == ((Socks5CommandType) obj).byteValue; 73 | } 74 | 75 | @Override 76 | public int compareTo(Socks5CommandType o) { 77 | return byteValue - o.byteValue; 78 | } 79 | 80 | @Override 81 | public String toString() { 82 | String text = this.text; 83 | if (text == null) { 84 | this.text = text = name + '(' + (byteValue & 0xFF) + ')'; 85 | } 86 | return text; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5AddressType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | /** 21 | * The type of address in {@link Socks5CommandRequest} and {@link Socks5CommandResponse}. 22 | */ 23 | public class Socks5AddressType implements Comparable { 24 | 25 | public static final Socks5AddressType IPv4 = new Socks5AddressType(0x01, "IPv4"); 26 | public static final Socks5AddressType DOMAIN = new Socks5AddressType(0x03, "DOMAIN"); 27 | public static final Socks5AddressType IPv6 = new Socks5AddressType(0x04, "IPv6"); 28 | 29 | public static Socks5AddressType valueOf(byte b) { 30 | switch (b) { 31 | case 0x01: 32 | return IPv4; 33 | case 0x03: 34 | return DOMAIN; 35 | case 0x04: 36 | return IPv6; 37 | } 38 | 39 | return new Socks5AddressType(b); 40 | } 41 | 42 | private final byte byteValue; 43 | private final String name; 44 | private String text; 45 | 46 | public Socks5AddressType(int byteValue) { 47 | this(byteValue, "UNKNOWN"); 48 | } 49 | 50 | public Socks5AddressType(int byteValue, String name) { 51 | requireNonNull(name, "name"); 52 | 53 | this.byteValue = (byte) byteValue; 54 | this.name = name; 55 | } 56 | 57 | public byte byteValue() { 58 | return byteValue; 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return byteValue; 64 | } 65 | 66 | @Override 67 | public boolean equals(Object obj) { 68 | if (!(obj instanceof Socks5AddressType)) { 69 | return false; 70 | } 71 | 72 | return byteValue == ((Socks5AddressType) obj).byteValue; 73 | } 74 | 75 | @Override 76 | public int compareTo(Socks5AddressType o) { 77 | return byteValue - o.byteValue; 78 | } 79 | 80 | @Override 81 | public String toString() { 82 | String text = this.text; 83 | if (text == null) { 84 | this.text = text = name + '(' + (byteValue & 0xFF) + ')'; 85 | } 86 | return text; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5PasswordAuthStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | /** 21 | * The status of {@link Socks5PasswordAuthResponse}. 22 | */ 23 | public class Socks5PasswordAuthStatus implements Comparable { 24 | 25 | public static final Socks5PasswordAuthStatus SUCCESS = new Socks5PasswordAuthStatus(0x00, "SUCCESS"); 26 | public static final Socks5PasswordAuthStatus FAILURE = new Socks5PasswordAuthStatus(0xFF, "FAILURE"); 27 | 28 | public static Socks5PasswordAuthStatus valueOf(byte b) { 29 | switch (b) { 30 | case 0x00: 31 | return SUCCESS; 32 | case (byte) 0xFF: 33 | return FAILURE; 34 | } 35 | 36 | return new Socks5PasswordAuthStatus(b); 37 | } 38 | 39 | private final byte byteValue; 40 | private final String name; 41 | private String text; 42 | 43 | public Socks5PasswordAuthStatus(int byteValue) { 44 | this(byteValue, "UNKNOWN"); 45 | } 46 | 47 | public Socks5PasswordAuthStatus(int byteValue, String name) { 48 | requireNonNull(name, "name"); 49 | 50 | this.byteValue = (byte) byteValue; 51 | this.name = name; 52 | } 53 | 54 | public byte byteValue() { 55 | return byteValue; 56 | } 57 | 58 | public boolean isSuccess() { 59 | return byteValue == 0; 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | return byteValue; 65 | } 66 | 67 | @Override 68 | public boolean equals(Object obj) { 69 | if (!(obj instanceof Socks5PasswordAuthStatus)) { 70 | return false; 71 | } 72 | 73 | return byteValue == ((Socks5PasswordAuthStatus) obj).byteValue; 74 | } 75 | 76 | @Override 77 | public int compareTo(Socks5PasswordAuthStatus o) { 78 | return byteValue - o.byteValue; 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | String text = this.text; 84 | if (text == null) { 85 | this.text = text = name + '(' + (byteValue & 0xFF) + ')'; 86 | } 87 | return text; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /codec-socks/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.netty.contrib 7 | netty-socks-proxy-parent 8 | 5.0.0.Alpha3-SNAPSHOT 9 | 10 | 11 | netty-codec-socks 12 | 5.0.0.Alpha3-SNAPSHOT 13 | Netty/Codec/Socks 14 | jar 15 | 16 | 17 | io.netty.contrib.codec.socks 18 | 19 | 20 | 21 | 22 | io.netty 23 | netty5-common 24 | ${netty.version} 25 | 26 | 27 | io.netty 28 | netty5-buffer 29 | ${netty.version} 30 | 31 | 32 | io.netty 33 | netty5-transport 34 | ${netty.version} 35 | 36 | 37 | io.netty 38 | netty5-codec 39 | ${netty.version} 40 | 41 | 42 | 43 | org.junit.jupiter 44 | junit-jupiter-engine 45 | test 46 | 47 | 48 | org.assertj 49 | assertj-core 50 | test 51 | 52 | 53 | org.slf4j 54 | slf4j-api 55 | 1.7.32 56 | 57 | 58 | 59 | 60 | org.reflections 61 | reflections 62 | 63 | 64 | com.google.code.gson 65 | gson 66 | 67 | 68 | com.google.guava 69 | guava 70 | 71 | 72 | io.netty 73 | netty5-transport 74 | test-jar 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socks/SocksAuthRequestDecoderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.embedded.EmbeddedChannel; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | import static org.junit.jupiter.api.Assertions.assertFalse; 24 | import static org.junit.jupiter.api.Assertions.assertNull; 25 | 26 | public class SocksAuthRequestDecoderTest { 27 | 28 | private static final String username = "testUserName"; 29 | private static final String password = "testPassword"; 30 | 31 | @Test 32 | public void testAuthRequestDecoder() { 33 | SocksAuthRequest msg = new SocksAuthRequest(username, password); 34 | SocksAuthRequestDecoder decoder = new SocksAuthRequestDecoder(); 35 | EmbeddedChannel embedder = new EmbeddedChannel(decoder); 36 | SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg); 37 | msg = embedder.readInbound(); 38 | assertEquals(username, msg.username()); 39 | assertEquals(password, msg.password()); 40 | assertNull(embedder.readInbound()); 41 | } 42 | 43 | @Test 44 | public void testAuthRequestDecoderPartialSend() { 45 | EmbeddedChannel ch = new EmbeddedChannel(new SocksAuthRequestDecoder()); 46 | Buffer buffer = ch.bufferAllocator().allocate(16); 47 | 48 | // Send username and password size 49 | buffer.writeByte(SocksSubnegotiationVersion.AUTH_PASSWORD.byteValue()); 50 | buffer.writeByte((byte) username.length()); 51 | buffer.writeBytes(username.getBytes()); 52 | buffer.writeByte((byte) password.length()); 53 | ch.writeInbound(buffer); 54 | 55 | // Check that channel is empty 56 | assertNull(ch.readInbound()); 57 | 58 | // Send password 59 | Buffer buffer2 = ch.bufferAllocator().allocate(16); 60 | buffer2.writeBytes(password.getBytes()); 61 | ch.writeInbound(buffer2); 62 | 63 | // Read message from channel 64 | SocksAuthRequest msg = ch.readInbound(); 65 | 66 | // Check message 67 | assertEquals(username, msg.username()); 68 | assertEquals(password, msg.password()); 69 | 70 | assertFalse(ch.finishAndReleaseAll()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5InitialRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.handler.codec.DecoderResult; 19 | import io.netty5.util.internal.StringUtil; 20 | 21 | import java.util.ArrayList; 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | import static io.netty5.util.internal.ObjectUtil.checkNonEmpty; 26 | import static java.util.Objects.requireNonNull; 27 | 28 | /** 29 | * The default {@link Socks5InitialRequest}. 30 | */ 31 | public class DefaultSocks5InitialRequest extends AbstractSocks5Message implements Socks5InitialRequest { 32 | 33 | private final List authMethods; 34 | 35 | public DefaultSocks5InitialRequest(Socks5AuthMethod... authMethods) { 36 | requireNonNull(authMethods, "authMethods"); 37 | 38 | List list = new ArrayList<>(authMethods.length); 39 | for (Socks5AuthMethod m: authMethods) { 40 | if (m == null) { 41 | break; 42 | } 43 | list.add(m); 44 | } 45 | 46 | this.authMethods = Collections.unmodifiableList(checkNonEmpty(list, "list")); 47 | } 48 | 49 | public DefaultSocks5InitialRequest(Iterable authMethods) { 50 | requireNonNull(authMethods, "authMethods"); 51 | 52 | List list = new ArrayList<>(); 53 | for (Socks5AuthMethod m: authMethods) { 54 | if (m == null) { 55 | break; 56 | } 57 | list.add(m); 58 | } 59 | 60 | this.authMethods = Collections.unmodifiableList(checkNonEmpty(list, "list")); 61 | } 62 | 63 | @Override 64 | public List authMethods() { 65 | return authMethods; 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | StringBuilder buf = new StringBuilder(StringUtil.simpleClassName(this)); 71 | 72 | DecoderResult decoderResult = decoderResult(); 73 | if (!decoderResult.isSuccess()) { 74 | buf.append("(decoderResult: "); 75 | buf.append(decoderResult); 76 | buf.append(", authMethods: "); 77 | } else { 78 | buf.append("(authMethods: "); 79 | } 80 | buf.append(authMethods()); 81 | buf.append(')'); 82 | 83 | return buf.toString(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5AuthMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | /** 21 | * The authentication method of SOCKS5. 22 | */ 23 | public class Socks5AuthMethod implements Comparable { 24 | 25 | public static final Socks5AuthMethod NO_AUTH = new Socks5AuthMethod(0x00, "NO_AUTH"); 26 | public static final Socks5AuthMethod GSSAPI = new Socks5AuthMethod(0x01, "GSSAPI"); 27 | public static final Socks5AuthMethod PASSWORD = new Socks5AuthMethod(0x02, "PASSWORD"); 28 | 29 | /** 30 | * Indicates that the server does not accept any authentication methods the client proposed. 31 | */ 32 | public static final Socks5AuthMethod UNACCEPTED = new Socks5AuthMethod(0xff, "UNACCEPTED"); 33 | 34 | public static Socks5AuthMethod valueOf(byte b) { 35 | switch (b) { 36 | case 0x00: 37 | return NO_AUTH; 38 | case 0x01: 39 | return GSSAPI; 40 | case 0x02: 41 | return PASSWORD; 42 | case (byte) 0xFF: 43 | return UNACCEPTED; 44 | } 45 | 46 | return new Socks5AuthMethod(b); 47 | } 48 | 49 | private final byte byteValue; 50 | private final String name; 51 | private String text; 52 | 53 | public Socks5AuthMethod(int byteValue) { 54 | this(byteValue, "UNKNOWN"); 55 | } 56 | 57 | public Socks5AuthMethod(int byteValue, String name) { 58 | requireNonNull(name, "name"); 59 | 60 | this.byteValue = (byte) byteValue; 61 | this.name = name; 62 | } 63 | 64 | public byte byteValue() { 65 | return byteValue; 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | return byteValue; 71 | } 72 | 73 | @Override 74 | public boolean equals(Object obj) { 75 | if (!(obj instanceof Socks5AuthMethod)) { 76 | return false; 77 | } 78 | 79 | return byteValue == ((Socks5AuthMethod) obj).byteValue; 80 | } 81 | 82 | @Override 83 | public int compareTo(Socks5AuthMethod o) { 84 | return byteValue - o.byteValue; 85 | } 86 | 87 | @Override 88 | public String toString() { 89 | String text = this.text; 90 | if (text == null) { 91 | this.text = text = name + '(' + (byteValue & 0xFF) + ')'; 92 | } 93 | return text; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /handler-proxy/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.netty.contrib 7 | netty-socks-proxy-parent 8 | 5.0.0.Alpha3-SNAPSHOT 9 | 10 | 11 | netty-handler-proxy 12 | 5.0.0.Alpha3-SNAPSHOT 13 | 14 | 15 | 16 | 17 | kr.motd.maven 18 | os-maven-plugin 19 | 1.7.0 20 | 21 | 22 | 23 | 24 | 25 | 26 | io.netty.contrib 27 | netty-codec-socks 28 | ${project.version} 29 | 30 | 31 | io.netty 32 | netty5-handler 33 | ${netty.version} 34 | 35 | 36 | io.netty 37 | netty5-codec-http 38 | ${netty.version} 39 | 40 | 41 | 42 | org.junit.jupiter 43 | junit-jupiter-engine 44 | test 45 | 46 | 47 | org.junit.jupiter 48 | junit-jupiter-params 49 | test 50 | 51 | 52 | org.assertj 53 | assertj-core 54 | test 55 | 56 | 57 | org.mockito 58 | mockito-core 59 | 4.1.0 60 | test 61 | 62 | 63 | 64 | 65 | org.reflections 66 | reflections 67 | 68 | 69 | com.google.code.gson 70 | gson 71 | 72 | 73 | com.google.guava 74 | guava 75 | 76 | 77 | io.netty 78 | netty5-transport 79 | test-jar 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksInitRequestDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.ByteToMessageDecoder; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Collections; 24 | import java.util.List; 25 | 26 | /** 27 | * Decodes {@link Buffer}s into {@link SocksInitRequest}. 28 | * Before returning SocksRequest decoder removes itself from pipeline. 29 | */ 30 | public class SocksInitRequestDecoder extends ByteToMessageDecoder { 31 | 32 | private enum State { 33 | CHECK_PROTOCOL_VERSION, 34 | READ_AUTH_SCHEMES 35 | } 36 | private State state = State.CHECK_PROTOCOL_VERSION; 37 | 38 | @Override 39 | protected void decode(ChannelHandlerContext ctx, Buffer buffer) throws Exception { 40 | switch (state) { 41 | case CHECK_PROTOCOL_VERSION: { 42 | if (buffer.readableBytes() < 1) { 43 | return; 44 | } 45 | if (buffer.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) { 46 | ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST); 47 | break; 48 | } 49 | state = State.READ_AUTH_SCHEMES; 50 | } 51 | case READ_AUTH_SCHEMES: { 52 | if (buffer.readableBytes() < 1) { 53 | return; 54 | } 55 | final byte authSchemeNum = buffer.getByte(buffer.readerOffset()); 56 | if (buffer.readableBytes() < 1 + authSchemeNum) { 57 | return; 58 | } 59 | buffer.skipReadableBytes(1); 60 | final List authSchemes; 61 | if (authSchemeNum > 0) { 62 | authSchemes = new ArrayList<>(authSchemeNum); 63 | for (int i = 0; i < authSchemeNum; i++) { 64 | authSchemes.add(SocksAuthScheme.valueOf(buffer.readByte())); 65 | } 66 | } else { 67 | authSchemes = Collections.emptyList(); 68 | } 69 | ctx.fireChannelRead(new SocksInitRequest(authSchemes)); 70 | break; 71 | } 72 | default: { 73 | throw new Error(); 74 | } 75 | } 76 | ctx.pipeline().remove(this); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5AddressDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.handler.codec.DecoderException; 20 | import java.nio.charset.StandardCharsets; 21 | import io.netty5.util.NetUtil; 22 | 23 | /** 24 | * Decodes a SOCKS5 address field into its string representation. 25 | * 26 | * @see Socks5CommandRequestDecoder 27 | * @see Socks5CommandResponseDecoder 28 | */ 29 | public interface Socks5AddressDecoder { 30 | 31 | Socks5AddressDecoder DEFAULT = new Socks5AddressDecoder() { 32 | 33 | private static final int IPv6_LEN = 16; 34 | 35 | @Override 36 | public String decodeAddress(Socks5AddressType addrType, Buffer in) { 37 | int readableBytes = in.readableBytes(); 38 | if (addrType == Socks5AddressType.IPv4) { 39 | if (readableBytes < 4) { 40 | return null; 41 | } 42 | return NetUtil.intToIpAddress(in.readInt()); 43 | } 44 | if (addrType == Socks5AddressType.DOMAIN) { 45 | if (readableBytes < 1) { 46 | return null; 47 | } 48 | final int length = in.getUnsignedByte(in.readerOffset()); 49 | if (readableBytes - 1 < length) { 50 | return null; 51 | } 52 | in.skipReadableBytes(1); 53 | return in.readCharSequence(length, StandardCharsets.US_ASCII).toString(); 54 | } 55 | if (addrType == Socks5AddressType.IPv6) { 56 | if (readableBytes < IPv6_LEN) { 57 | return null; 58 | } 59 | byte[] tmp = new byte[IPv6_LEN]; 60 | in.readBytes(tmp, 0, tmp.length); 61 | return NetUtil.bytesToIpAddress(tmp); 62 | } else { 63 | throw new DecoderException("unsupported address type: " + (addrType.byteValue() & 0xFF)); 64 | } 65 | } 66 | }; 67 | 68 | /** 69 | * Decodes a SOCKS5 address field into its string representation. 70 | * 71 | * @param addrType the type of the address 72 | * @param in the input buffer which contains the SOCKS5 address field at its reader index 73 | * @return the address or {@code null} if not enough bytes are readable yet. 74 | */ 75 | String decodeAddress(Socks5AddressType addrType, Buffer in) throws Exception; 76 | } 77 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/Socks4CommandStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | /** 21 | * The status of {@link Socks4CommandResponse}. 22 | */ 23 | public class Socks4CommandStatus implements Comparable { 24 | 25 | public static final Socks4CommandStatus SUCCESS = new Socks4CommandStatus(0x5a, "SUCCESS"); 26 | public static final Socks4CommandStatus REJECTED_OR_FAILED = new Socks4CommandStatus(0x5b, "REJECTED_OR_FAILED"); 27 | public static final Socks4CommandStatus IDENTD_UNREACHABLE = new Socks4CommandStatus(0x5c, "IDENTD_UNREACHABLE"); 28 | public static final Socks4CommandStatus IDENTD_AUTH_FAILURE = new Socks4CommandStatus(0x5d, "IDENTD_AUTH_FAILURE"); 29 | 30 | public static Socks4CommandStatus valueOf(byte b) { 31 | switch (b) { 32 | case 0x5a: 33 | return SUCCESS; 34 | case 0x5b: 35 | return REJECTED_OR_FAILED; 36 | case 0x5c: 37 | return IDENTD_UNREACHABLE; 38 | case 0x5d: 39 | return IDENTD_AUTH_FAILURE; 40 | } 41 | 42 | return new Socks4CommandStatus(b); 43 | } 44 | 45 | private final byte byteValue; 46 | private final String name; 47 | private String text; 48 | 49 | public Socks4CommandStatus(int byteValue) { 50 | this(byteValue, "UNKNOWN"); 51 | } 52 | 53 | public Socks4CommandStatus(int byteValue, String name) { 54 | requireNonNull(name, "name"); 55 | 56 | this.byteValue = (byte) byteValue; 57 | this.name = name; 58 | } 59 | 60 | public byte byteValue() { 61 | return byteValue; 62 | } 63 | 64 | public boolean isSuccess() { 65 | return byteValue == 0x5a; 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | return byteValue; 71 | } 72 | 73 | @Override 74 | public boolean equals(Object obj) { 75 | if (!(obj instanceof Socks4CommandStatus)) { 76 | return false; 77 | } 78 | 79 | return byteValue == ((Socks4CommandStatus) obj).byteValue; 80 | } 81 | 82 | @Override 83 | public int compareTo(Socks4CommandStatus o) { 84 | return byteValue - o.byteValue; 85 | } 86 | 87 | @Override 88 | public String toString() { 89 | String text = this.text; 90 | if (text == null) { 91 | this.text = text = name + '(' + (byteValue & 0xFF) + ')'; 92 | } 93 | return text; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksAuthRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.util.CharsetUtil; 20 | 21 | import java.nio.charset.StandardCharsets; 22 | import java.nio.charset.CharsetEncoder; 23 | 24 | import static java.util.Objects.requireNonNull; 25 | 26 | /** 27 | * An socks auth request. 28 | * 29 | * @see SocksAuthResponse 30 | * @see SocksAuthRequestDecoder 31 | */ 32 | public final class SocksAuthRequest extends SocksRequest { 33 | private static final SocksSubnegotiationVersion SUBNEGOTIATION_VERSION = SocksSubnegotiationVersion.AUTH_PASSWORD; 34 | private final String username; 35 | private final String password; 36 | 37 | public SocksAuthRequest(String username, String password) { 38 | super(SocksRequestType.AUTH); 39 | requireNonNull(username, "username"); 40 | requireNonNull(password, "password"); 41 | 42 | final CharsetEncoder asciiEncoder = CharsetUtil.encoder(StandardCharsets.US_ASCII); 43 | if (!asciiEncoder.canEncode(username) || !asciiEncoder.canEncode(password)) { 44 | throw new IllegalArgumentException( 45 | "username: " + username + " or password: **** values should be in pure ascii"); 46 | } 47 | if (username.length() > 255) { 48 | throw new IllegalArgumentException("username: " + username + " exceeds 255 char limit"); 49 | } 50 | if (password.length() > 255) { 51 | throw new IllegalArgumentException("password: **** exceeds 255 char limit"); 52 | } 53 | this.username = username; 54 | this.password = password; 55 | } 56 | 57 | /** 58 | * Returns username that needs to be authenticated 59 | * 60 | * @return username that needs to be authenticated 61 | */ 62 | public String username() { 63 | return username; 64 | } 65 | 66 | /** 67 | * Returns password that needs to be validated 68 | * 69 | * @return password that needs to be validated 70 | */ 71 | public String password() { 72 | return password; 73 | } 74 | 75 | @Override 76 | public void encodeAsBuffer(Buffer buffer) { 77 | buffer.writeByte(SUBNEGOTIATION_VERSION.byteValue()); 78 | buffer.writeByte((byte) username.length()); 79 | buffer.writeCharSequence(username, StandardCharsets.US_ASCII); 80 | buffer.writeByte((byte) password.length()); 81 | buffer.writeCharSequence(password, StandardCharsets.US_ASCII); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5PasswordAuthRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.handler.codec.DecoderResult; 19 | import io.netty5.util.internal.StringUtil; 20 | 21 | import static java.util.Objects.requireNonNull; 22 | 23 | /** 24 | * The default {@link Socks5PasswordAuthRequest}. 25 | */ 26 | public class DefaultSocks5PasswordAuthRequest extends AbstractSocks5Message implements Socks5PasswordAuthRequest { 27 | 28 | private final String username; 29 | private final String password; 30 | 31 | public DefaultSocks5PasswordAuthRequest(String username, String password) { 32 | requireNonNull(username, "username"); 33 | requireNonNull(password, "password"); 34 | 35 | if (username.length() > 255) { 36 | throw new IllegalArgumentException("username: **** (expected: less than 256 chars)"); 37 | } 38 | if (password.length() > 255) { 39 | throw new IllegalArgumentException("password: **** (expected: less than 256 chars)"); 40 | } 41 | if (containNonAscii(username)) { 42 | throw new IllegalArgumentException("username: **** (contains non-ASCII characters, which is not allowed)"); 43 | } 44 | if (containNonAscii(password)) { 45 | throw new IllegalArgumentException("password: **** (contains non-ASCII characters, which is not allowed)"); 46 | } 47 | 48 | this.username = username; 49 | this.password = password; 50 | } 51 | 52 | private static boolean containNonAscii(String string) { 53 | int length = string.length(); 54 | for (int i = 0; i < length; i++) { 55 | char c = string.charAt(i); 56 | if (c > 127) { 57 | return true; 58 | } 59 | } 60 | return false; 61 | } 62 | 63 | @Override 64 | public String username() { 65 | return username; 66 | } 67 | 68 | @Override 69 | public String password() { 70 | return password; 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | StringBuilder buf = new StringBuilder(StringUtil.simpleClassName(this)); 76 | 77 | DecoderResult decoderResult = decoderResult(); 78 | if (!decoderResult.isSuccess()) { 79 | buf.append("(decoderResult: "); 80 | buf.append(decoderResult); 81 | buf.append(", username: "); 82 | } else { 83 | buf.append("(username: "); 84 | } 85 | buf.append(username()); 86 | buf.append(", password: ****)"); 87 | 88 | return buf.toString(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /handler-proxy/src/main/java/io/netty/contrib/handler/proxy/ProxyConnectionEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.proxy; 17 | 18 | import io.netty5.util.internal.StringUtil; 19 | 20 | import java.net.SocketAddress; 21 | 22 | import static java.util.Objects.requireNonNull; 23 | 24 | public final class ProxyConnectionEvent { 25 | 26 | private final String protocol; 27 | private final String authScheme; 28 | private final SocketAddress proxyAddress; 29 | private final SocketAddress destinationAddress; 30 | private String strVal; 31 | 32 | /** 33 | * Creates a new event that indicates a successful connection attempt to the destination address. 34 | */ 35 | public ProxyConnectionEvent( 36 | String protocol, String authScheme, SocketAddress proxyAddress, SocketAddress destinationAddress) { 37 | requireNonNull(protocol, "protocol"); 38 | requireNonNull(authScheme, "authScheme"); 39 | requireNonNull(proxyAddress, "proxyAddress"); 40 | requireNonNull(destinationAddress, "destinationAddress"); 41 | 42 | this.protocol = protocol; 43 | this.authScheme = authScheme; 44 | this.proxyAddress = proxyAddress; 45 | this.destinationAddress = destinationAddress; 46 | } 47 | 48 | /** 49 | * Returns the name of the proxy protocol in use. 50 | */ 51 | public String protocol() { 52 | return protocol; 53 | } 54 | 55 | /** 56 | * Returns the name of the authentication scheme in use. 57 | */ 58 | public String authScheme() { 59 | return authScheme; 60 | } 61 | 62 | /** 63 | * Returns the address of the proxy server. 64 | */ 65 | @SuppressWarnings("unchecked") 66 | public T proxyAddress() { 67 | return (T) proxyAddress; 68 | } 69 | 70 | /** 71 | * Returns the address of the destination. 72 | */ 73 | @SuppressWarnings("unchecked") 74 | public T destinationAddress() { 75 | return (T) destinationAddress; 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | if (strVal != null) { 81 | return strVal; 82 | } 83 | 84 | StringBuilder buf = new StringBuilder(128) 85 | .append(StringUtil.simpleClassName(this)) 86 | .append('(') 87 | .append(protocol) 88 | .append(", ") 89 | .append(authScheme) 90 | .append(", ") 91 | .append(proxyAddress) 92 | .append(" => ") 93 | .append(destinationAddress) 94 | .append(')'); 95 | 96 | return strVal = buf.toString(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socks/SocksAuthRequestDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.ByteToMessageDecoder; 21 | import java.nio.charset.StandardCharsets; 22 | 23 | /** 24 | * Decodes {@link Buffer}s into {@link SocksAuthRequest}. 25 | * Before returning SocksRequest decoder removes itself from pipeline. 26 | */ 27 | public class SocksAuthRequestDecoder extends ByteToMessageDecoder { 28 | 29 | private enum State { 30 | CHECK_PROTOCOL_VERSION, 31 | READ_USERNAME, 32 | READ_PASSWORD 33 | } 34 | private State state = State.CHECK_PROTOCOL_VERSION; 35 | private String username; 36 | 37 | @Override 38 | protected void decode(ChannelHandlerContext ctx, Buffer buffer) throws Exception { 39 | switch (state) { 40 | case CHECK_PROTOCOL_VERSION: { 41 | if (buffer.readableBytes() < 1) { 42 | return; 43 | } 44 | if (buffer.readByte() != SocksSubnegotiationVersion.AUTH_PASSWORD.byteValue()) { 45 | ctx.fireChannelRead(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST); 46 | break; 47 | } 48 | state = State.READ_USERNAME; 49 | } 50 | case READ_USERNAME: { 51 | if (buffer.readableBytes() < 1) { 52 | return; 53 | } 54 | int fieldLength = buffer.getByte(buffer.readerOffset()); 55 | if (buffer.readableBytes() < 1 + fieldLength) { 56 | return; 57 | } 58 | buffer.skipReadableBytes(1); 59 | username = buffer.readCharSequence(fieldLength, StandardCharsets.US_ASCII).toString(); 60 | state = State.READ_PASSWORD; 61 | } 62 | case READ_PASSWORD: { 63 | if (buffer.readableBytes() < 1) { 64 | return; 65 | } 66 | int fieldLength = buffer.getByte(buffer.readerOffset()); 67 | if (buffer.readableBytes() < 1 + fieldLength) { 68 | return; 69 | } 70 | buffer.skipReadableBytes(1); 71 | String password = buffer.readCharSequence(fieldLength, StandardCharsets.US_ASCII).toString(); 72 | ctx.fireChannelRead(new SocksAuthRequest(username, password)); 73 | break; 74 | } 75 | default: { 76 | throw new Error(); 77 | } 78 | } 79 | ctx.pipeline().remove(this); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5PasswordAuthRequestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertThrows; 21 | 22 | public class DefaultSocks5PasswordAuthRequestTest { 23 | @Test 24 | public void testConstructorParamsAreNotNull() { 25 | assertThrows(NullPointerException.class, () -> new DefaultSocks5PasswordAuthRequest(null, "")); 26 | assertThrows(NullPointerException.class, () -> new DefaultSocks5PasswordAuthRequest("", null)); 27 | } 28 | 29 | @Test 30 | public void testUsernameOrPasswordIsNotAscii() { 31 | assertThrows(IllegalArgumentException.class, 32 | () -> new DefaultSocks5PasswordAuthRequest("παράδειγμα.δοκιμή", "password")); 33 | assertThrows(IllegalArgumentException.class, 34 | () -> new DefaultSocks5PasswordAuthRequest("username", "παράδειγμα.δοκιμή")); 35 | } 36 | 37 | @Test 38 | public void testUsernameOrPasswordLengthIsLessThan255Chars() { 39 | assertThrows(IllegalArgumentException.class, () -> new DefaultSocks5PasswordAuthRequest( 40 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 41 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 42 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 43 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 44 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 45 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 46 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 47 | "passwordpasswordpasswordpasswordpasswordpasswordpassword", 48 | "password")); 49 | assertThrows(IllegalArgumentException.class, () -> new DefaultSocks5PasswordAuthRequest("password", 50 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 51 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 52 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 53 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 54 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 55 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 56 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 57 | "passwordpasswordpasswordpasswordpasswordpasswordpassword")); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5PasswordAuthResponseDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.ByteToMessageDecoder; 21 | import io.netty5.handler.codec.DecoderException; 22 | import io.netty5.handler.codec.DecoderResult; 23 | 24 | /** 25 | * Decodes a single {@link Socks5PasswordAuthResponse} from the inbound {@link Buffer}s. 26 | * On successful decode, this decoder will forward the received data to the next handler, so that 27 | * other handler can remove or replace this decoder later. On failed decode, this decoder will 28 | * discard the received data, so that other handler closes the connection later. 29 | */ 30 | public class Socks5PasswordAuthResponseDecoder extends ByteToMessageDecoder { 31 | 32 | private enum State { 33 | INIT, 34 | SUCCESS, 35 | FAILURE 36 | } 37 | 38 | private State state = State.INIT; 39 | 40 | @Override 41 | protected void decode(ChannelHandlerContext ctx, Buffer in) throws Exception { 42 | try { 43 | switch (state) { 44 | case INIT: { 45 | if (in.readableBytes() < 2) { 46 | return; 47 | } 48 | final byte version = in.readByte(); 49 | if (version != 1) { 50 | throw new DecoderException("unsupported subnegotiation version: " + version + " (expected: 1)"); 51 | } 52 | 53 | ctx.fireChannelRead( 54 | new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.valueOf(in.readByte()))); 55 | state = State.SUCCESS; 56 | } 57 | case SUCCESS: { 58 | int readableBytes = actualReadableBytes(); 59 | if (readableBytes > 0) { 60 | ctx.fireChannelRead(in.readSplit(readableBytes)); 61 | } 62 | break; 63 | } 64 | case FAILURE: { 65 | in.skipReadableBytes(actualReadableBytes()); 66 | break; 67 | } 68 | } 69 | } catch (Exception e) { 70 | fail(ctx, e); 71 | } 72 | } 73 | 74 | private void fail(ChannelHandlerContext ctx, Exception cause) { 75 | if (!(cause instanceof DecoderException)) { 76 | cause = new DecoderException(cause); 77 | } 78 | 79 | state = State.FAILURE; 80 | 81 | Socks5Message m = new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.FAILURE); 82 | m.setDecoderResult(DecoderResult.failure(cause)); 83 | ctx.fireChannelRead(m); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5CommandRequestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertThrows; 21 | 22 | public class DefaultSocks5CommandRequestTest { 23 | @Test 24 | public void testConstructorParamsAreNotNull() { 25 | assertThrows(NullPointerException.class, 26 | () -> new DefaultSocks5CommandRequest(null, Socks5AddressType.DOMAIN, "", 1)); 27 | assertThrows(NullPointerException.class, 28 | () -> new DefaultSocks5CommandRequest(Socks5CommandType.CONNECT, null, "", 1)); 29 | assertThrows(NullPointerException.class, 30 | () -> new DefaultSocks5CommandRequest(Socks5CommandType.CONNECT, Socks5AddressType.DOMAIN, null, 1)); 31 | } 32 | 33 | @Test 34 | public void testIPv4CorrectAddress() { 35 | assertThrows(IllegalArgumentException.class, () -> new DefaultSocks5CommandRequest( 36 | Socks5CommandType.BIND, Socks5AddressType.IPv4, "54.54.1111.253", 1)); 37 | } 38 | 39 | @Test 40 | public void testIPv6CorrectAddress() { 41 | assertThrows(IllegalArgumentException.class, () -> new DefaultSocks5CommandRequest( 42 | Socks5CommandType.BIND, Socks5AddressType.IPv6, "xxx:xxx:xxx", 1)); 43 | } 44 | 45 | @Test 46 | public void testIDNNotExceeds255CharsLimit() { 47 | assertThrows(IllegalArgumentException.class, () -> new DefaultSocks5CommandRequest( 48 | Socks5CommandType.BIND, Socks5AddressType.DOMAIN, 49 | "παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" + 50 | "παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" + 51 | "παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" + 52 | "παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή", 1)); 53 | } 54 | 55 | @Test 56 | public void testValidPortRange() { 57 | assertThrows(IllegalArgumentException.class, () -> new DefaultSocks5CommandRequest( 58 | Socks5CommandType.BIND, Socks5AddressType.DOMAIN, "παράδειγμα.δοκιμήπαράδει", -1)); 59 | assertThrows(IllegalArgumentException.class, () -> new DefaultSocks5CommandRequest( 60 | Socks5CommandType.BIND, Socks5AddressType.DOMAIN, "παράδειγμα.δοκιμήπαράδει", 65536)); 61 | 62 | new DefaultSocks5CommandRequest(Socks5CommandType.BIND, Socks5AddressType.DOMAIN, 63 | "παράδειγμα.δοκιμήπαράδει", 0); 64 | new DefaultSocks5CommandRequest(Socks5CommandType.BIND, Socks5AddressType.DOMAIN, 65 | "παράδειγμα.δοκιμήπαράδει", 65535); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5InitialResponseDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.ByteToMessageDecoder; 21 | import io.netty5.handler.codec.DecoderException; 22 | import io.netty5.handler.codec.DecoderResult; 23 | import io.netty.contrib.handler.codec.socksx.SocksVersion; 24 | 25 | /** 26 | * Decodes a single {@link Socks5InitialResponse} from the inbound {@link Buffer}s. 27 | * On successful decode, this decoder will forward the received data to the next handler, so that 28 | * other handler can remove or replace this decoder later. On failed decode, this decoder will 29 | * discard the received data, so that other handler closes the connection later. 30 | */ 31 | public class Socks5InitialResponseDecoder extends ByteToMessageDecoder { 32 | 33 | private enum State { 34 | INIT, 35 | SUCCESS, 36 | FAILURE 37 | } 38 | 39 | private State state = State.INIT; 40 | 41 | @Override 42 | protected void decode(ChannelHandlerContext ctx, Buffer in) throws Exception { 43 | try { 44 | switch (state) { 45 | case INIT: { 46 | if (in.readableBytes() < 2) { 47 | return; 48 | } 49 | final byte version = in.readByte(); 50 | if (version != SocksVersion.SOCKS5.byteValue()) { 51 | throw new DecoderException( 52 | "unsupported version: " + version + " (expected: " + SocksVersion.SOCKS5.byteValue() + ')'); 53 | } 54 | 55 | final Socks5AuthMethod authMethod = Socks5AuthMethod.valueOf(in.readByte()); 56 | ctx.fireChannelRead(new DefaultSocks5InitialResponse(authMethod)); 57 | state = State.SUCCESS; 58 | } 59 | case SUCCESS: { 60 | int readableBytes = actualReadableBytes(); 61 | if (readableBytes > 0) { 62 | ctx.fireChannelRead(in.readSplit(readableBytes)); 63 | } 64 | break; 65 | } 66 | case FAILURE: { 67 | in.skipReadableBytes(actualReadableBytes()); 68 | break; 69 | } 70 | } 71 | } catch (Exception e) { 72 | fail(ctx, e); 73 | } 74 | } 75 | 76 | private void fail(ChannelHandlerContext ctx, Exception cause) { 77 | if (!(cause instanceof DecoderException)) { 78 | cause = new DecoderException(cause); 79 | } 80 | 81 | state = State.FAILURE; 82 | 83 | Socks5Message m = new DefaultSocks5InitialResponse(Socks5AuthMethod.UNACCEPTED); 84 | m.setDecoderResult(DecoderResult.failure(cause)); 85 | ctx.fireChannelRead(m); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/DefaultSocks4CommandResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty5.handler.codec.DecoderResult; 19 | import io.netty5.util.NetUtil; 20 | import io.netty5.util.internal.StringUtil; 21 | 22 | import static java.util.Objects.requireNonNull; 23 | 24 | /** 25 | * The default {@link Socks4CommandResponse}. 26 | */ 27 | public class DefaultSocks4CommandResponse extends AbstractSocks4Message implements Socks4CommandResponse { 28 | 29 | private final Socks4CommandStatus status; 30 | private final String dstAddr; 31 | private final int dstPort; 32 | 33 | /** 34 | * Creates a new instance. 35 | * 36 | * @param status the status of the response 37 | */ 38 | public DefaultSocks4CommandResponse(Socks4CommandStatus status) { 39 | this(status, null, 0); 40 | } 41 | 42 | /** 43 | * Creates a new instance. 44 | * 45 | * @param status the status of the response 46 | * @param dstAddr the {@code DSTIP} field of the response 47 | * @param dstPort the {@code DSTPORT} field of the response 48 | */ 49 | public DefaultSocks4CommandResponse(Socks4CommandStatus status, String dstAddr, int dstPort) { 50 | requireNonNull(status, "status"); 51 | if (dstAddr != null) { 52 | if (!NetUtil.isValidIpV4Address(dstAddr)) { 53 | throw new IllegalArgumentException( 54 | "dstAddr: " + dstAddr + " (expected: a valid IPv4 address)"); 55 | } 56 | } 57 | if (dstPort < 0 || dstPort > 65535) { 58 | throw new IllegalArgumentException("dstPort: " + dstPort + " (expected: 0~65535)"); 59 | } 60 | 61 | this.status = status; 62 | this.dstAddr = dstAddr; 63 | this.dstPort = dstPort; 64 | } 65 | 66 | @Override 67 | public Socks4CommandStatus status() { 68 | return status; 69 | } 70 | 71 | @Override 72 | public String dstAddr() { 73 | return dstAddr; 74 | } 75 | 76 | @Override 77 | public int dstPort() { 78 | return dstPort; 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | StringBuilder buf = new StringBuilder(96); 84 | buf.append(StringUtil.simpleClassName(this)); 85 | 86 | DecoderResult decoderResult = decoderResult(); 87 | if (!decoderResult.isSuccess()) { 88 | buf.append("(decoderResult: "); 89 | buf.append(decoderResult); 90 | buf.append(", dstAddr: "); 91 | } else { 92 | buf.append("(dstAddr: "); 93 | } 94 | buf.append(dstAddr()); 95 | buf.append(", dstPort: "); 96 | buf.append(dstPort()); 97 | buf.append(')'); 98 | 99 | return buf.toString(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /codec-socks/src/test/java/io/netty/contrib/handler/codec/socks/SocksAuthRequestTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socks; 17 | 18 | import org.junit.jupiter.api.Test; 19 | 20 | import static org.junit.jupiter.api.Assertions.assertTrue; 21 | 22 | public class SocksAuthRequestTest { 23 | @Test 24 | public void testConstructorParamsAreNotNull() { 25 | try { 26 | new SocksAuthRequest(null, ""); 27 | } catch (Exception e) { 28 | assertTrue(e instanceof NullPointerException); 29 | } 30 | try { 31 | new SocksAuthRequest("", null); 32 | } catch (Exception e) { 33 | assertTrue(e instanceof NullPointerException); 34 | } 35 | } 36 | 37 | @Test 38 | public void testUsernameOrPasswordIsNotAscii() { 39 | try { 40 | new SocksAuthRequest("παράδειγμα.δοκιμή", "password"); 41 | } catch (Exception e) { 42 | assertTrue(e instanceof IllegalArgumentException); 43 | } 44 | try { 45 | new SocksAuthRequest("username", "παράδειγμα.δοκιμή"); 46 | } catch (Exception e) { 47 | assertTrue(e instanceof IllegalArgumentException); 48 | } 49 | } 50 | 51 | @Test 52 | public void testUsernameOrPasswordLengthIsLessThan255Chars() { 53 | try { 54 | new SocksAuthRequest( 55 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 56 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 57 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 58 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 59 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 60 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 61 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 62 | "passwordpasswordpasswordpasswordpasswordpasswordpassword", 63 | "password"); 64 | } catch (Exception e) { 65 | assertTrue(e instanceof IllegalArgumentException); 66 | } 67 | try { 68 | new SocksAuthRequest("password", 69 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 70 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 71 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 72 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 73 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 74 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 75 | "passwordpasswordpasswordpasswordpasswordpasswordpassword" + 76 | "passwordpasswordpasswordpasswordpasswordpasswordpassword"); 77 | } catch (Exception e) { 78 | assertTrue(e instanceof IllegalArgumentException); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/Socks4ClientDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.ByteToMessageDecoder; 21 | import io.netty5.handler.codec.DecoderException; 22 | import io.netty5.handler.codec.DecoderResult; 23 | import io.netty5.util.NetUtil; 24 | 25 | /** 26 | * Decodes a single {@link Socks4CommandResponse} from the inbound {@link Buffer}s. 27 | * On successful decode, this decoder will forward the received data to the next handler, so that 28 | * other handler can remove this decoder later. On failed decode, this decoder will discard the 29 | * received data, so that other handler closes the connection later. 30 | */ 31 | public class Socks4ClientDecoder extends ByteToMessageDecoder { 32 | 33 | private enum State { 34 | START, 35 | SUCCESS, 36 | FAILURE 37 | } 38 | 39 | private State state = State.START; 40 | 41 | public Socks4ClientDecoder() { 42 | setSingleDecode(true); 43 | } 44 | 45 | @Override 46 | protected void decode(ChannelHandlerContext ctx, Buffer in) throws Exception { 47 | try { 48 | switch (state) { 49 | case START: { 50 | if (in.readableBytes() < 8) { 51 | // Not enough data to read. 52 | return; 53 | } 54 | final int version = in.readUnsignedByte(); 55 | if (version != 0) { 56 | throw new DecoderException("unsupported reply version: " + version + " (expected: 0)"); 57 | } 58 | 59 | final Socks4CommandStatus status = Socks4CommandStatus.valueOf(in.readByte()); 60 | final int dstPort = in.readUnsignedShort(); 61 | final String dstAddr = NetUtil.intToIpAddress(in.readInt()); 62 | 63 | ctx.fireChannelRead(new DefaultSocks4CommandResponse(status, dstAddr, dstPort)); 64 | state = State.SUCCESS; 65 | // fall-through 66 | } 67 | case SUCCESS: { 68 | int readableBytes = actualReadableBytes(); 69 | if (readableBytes > 0) { 70 | ctx.fireChannelRead(in.readSplit(readableBytes)); 71 | } 72 | break; 73 | } 74 | case FAILURE: { 75 | in.skipReadableBytes(actualReadableBytes()); 76 | break; 77 | } 78 | } 79 | } catch (Exception e) { 80 | fail(ctx, e); 81 | } 82 | } 83 | 84 | private void fail(ChannelHandlerContext ctx, Exception cause) { 85 | if (!(cause instanceof DecoderException)) { 86 | cause = new DecoderException(cause); 87 | } 88 | 89 | Socks4CommandResponse m = new DefaultSocks4CommandResponse(Socks4CommandStatus.REJECTED_OR_FAILED); 90 | m.setDecoderResult(DecoderResult.failure(cause)); 91 | ctx.fireChannelRead(m); 92 | 93 | state = State.FAILURE; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v4/DefaultSocks4CommandRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v4; 17 | 18 | import io.netty5.handler.codec.DecoderResult; 19 | import io.netty5.util.internal.StringUtil; 20 | 21 | import java.net.IDN; 22 | 23 | import static java.util.Objects.requireNonNull; 24 | 25 | /** 26 | * The default {@link Socks4CommandRequest}. 27 | */ 28 | public class DefaultSocks4CommandRequest extends AbstractSocks4Message implements Socks4CommandRequest { 29 | 30 | private final Socks4CommandType type; 31 | private final String dstAddr; 32 | private final int dstPort; 33 | private final String userId; 34 | 35 | /** 36 | * Creates a new instance. 37 | * 38 | * @param type the type of the request 39 | * @param dstAddr the {@code DSTIP} field of the request 40 | * @param dstPort the {@code DSTPORT} field of the request 41 | */ 42 | public DefaultSocks4CommandRequest(Socks4CommandType type, String dstAddr, int dstPort) { 43 | this(type, dstAddr, dstPort, ""); 44 | } 45 | 46 | /** 47 | * Creates a new instance. 48 | * 49 | * @param type the type of the request 50 | * @param dstAddr the {@code DSTIP} field of the request 51 | * @param dstPort the {@code DSTPORT} field of the request 52 | * @param userId the {@code USERID} field of the request 53 | */ 54 | public DefaultSocks4CommandRequest(Socks4CommandType type, String dstAddr, int dstPort, String userId) { 55 | requireNonNull(type, "type"); 56 | requireNonNull(dstAddr, "dstAddr"); 57 | if (dstPort <= 0 || dstPort >= 65536) { 58 | throw new IllegalArgumentException("dstPort: " + dstPort + " (expected: 1~65535)"); 59 | } 60 | requireNonNull(userId, "userId"); 61 | 62 | this.userId = userId; 63 | this.type = type; 64 | this.dstAddr = IDN.toASCII(dstAddr); 65 | this.dstPort = dstPort; 66 | } 67 | 68 | @Override 69 | public Socks4CommandType type() { 70 | return type; 71 | } 72 | 73 | @Override 74 | public String dstAddr() { 75 | return dstAddr; 76 | } 77 | 78 | @Override 79 | public int dstPort() { 80 | return dstPort; 81 | } 82 | 83 | @Override 84 | public String userId() { 85 | return userId; 86 | } 87 | 88 | @Override 89 | public String toString() { 90 | StringBuilder buf = new StringBuilder(128); 91 | buf.append(StringUtil.simpleClassName(this)); 92 | 93 | DecoderResult decoderResult = decoderResult(); 94 | if (!decoderResult.isSuccess()) { 95 | buf.append("(decoderResult: "); 96 | buf.append(decoderResult); 97 | buf.append(", type: "); 98 | } else { 99 | buf.append("(type: "); 100 | } 101 | buf.append(type()); 102 | buf.append(", dstAddr: "); 103 | buf.append(dstAddr()); 104 | buf.append(", dstPort: "); 105 | buf.append(dstPort()); 106 | buf.append(", userId: "); 107 | buf.append(userId()); 108 | buf.append(')'); 109 | 110 | return buf.toString(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5InitialRequestDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.ByteToMessageDecoder; 21 | import io.netty5.handler.codec.DecoderException; 22 | import io.netty5.handler.codec.DecoderResult; 23 | import io.netty.contrib.handler.codec.socksx.SocksVersion; 24 | 25 | /** 26 | * Decodes a single {@link Socks5InitialRequest} from the inbound {@link Buffer}s. 27 | * On successful decode, this decoder will forward the received data to the next handler, so that 28 | * other handler can remove or replace this decoder later. On failed decode, this decoder will 29 | * discard the received data, so that other handler closes the connection later. 30 | */ 31 | public class Socks5InitialRequestDecoder extends ByteToMessageDecoder { 32 | 33 | private enum State { 34 | INIT, 35 | SUCCESS, 36 | FAILURE 37 | } 38 | 39 | private State state = State.INIT; 40 | 41 | @Override 42 | protected void decode(ChannelHandlerContext ctx, Buffer in) throws Exception { 43 | try { 44 | switch (state) { 45 | case INIT: { 46 | if (in.readableBytes() < 2) { 47 | return; 48 | } 49 | int readerIndex = in.readerOffset(); 50 | final byte version = in.readByte(); 51 | if (version != SocksVersion.SOCKS5.byteValue()) { 52 | throw new DecoderException( 53 | "unsupported version: " + version + " (expected: " + SocksVersion.SOCKS5.byteValue() + ')'); 54 | } 55 | 56 | final int authMethodCnt = in.readUnsignedByte(); 57 | 58 | if (in.readableBytes() < authMethodCnt) { 59 | in.readerOffset(readerIndex); 60 | return; 61 | } 62 | final Socks5AuthMethod[] authMethods = new Socks5AuthMethod[authMethodCnt]; 63 | for (int i = 0; i < authMethodCnt; i++) { 64 | authMethods[i] = Socks5AuthMethod.valueOf(in.readByte()); 65 | } 66 | 67 | ctx.fireChannelRead(new DefaultSocks5InitialRequest(authMethods)); 68 | state = State.SUCCESS; 69 | } 70 | case SUCCESS: { 71 | int readableBytes = actualReadableBytes(); 72 | if (readableBytes > 0) { 73 | ctx.fireChannelRead(in.readSplit(readableBytes)); 74 | } 75 | break; 76 | } 77 | case FAILURE: { 78 | in.skipReadableBytes(actualReadableBytes()); 79 | break; 80 | } 81 | } 82 | } catch (Exception e) { 83 | fail(ctx, e); 84 | } 85 | } 86 | 87 | private void fail(ChannelHandlerContext ctx, Exception cause) { 88 | if (!(cause instanceof DecoderException)) { 89 | cause = new DecoderException(cause); 90 | } 91 | 92 | state = State.FAILURE; 93 | 94 | Socks5Message m = new DefaultSocks5InitialRequest(Socks5AuthMethod.NO_AUTH); 95 | m.setDecoderResult(DecoderResult.failure(cause)); 96 | ctx.fireChannelRead(m); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5PasswordAuthRequestDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.ByteToMessageDecoder; 21 | import io.netty5.handler.codec.DecoderException; 22 | import io.netty5.handler.codec.DecoderResult; 23 | import java.nio.charset.StandardCharsets; 24 | 25 | /** 26 | * Decodes a single {@link Socks5PasswordAuthRequest} from the inbound {@link Buffer}s. 27 | * On successful decode, this decoder will forward the received data to the next handler, so that 28 | * other handler can remove or replace this decoder later. On failed decode, this decoder will 29 | * discard the received data, so that other handler closes the connection later. 30 | */ 31 | public class Socks5PasswordAuthRequestDecoder extends ByteToMessageDecoder { 32 | 33 | private enum State { 34 | INIT, 35 | SUCCESS, 36 | FAILURE 37 | } 38 | 39 | private State state = State.INIT; 40 | 41 | @Override 42 | protected void decode(ChannelHandlerContext ctx, Buffer in) throws Exception { 43 | try { 44 | switch (state) { 45 | case INIT: { 46 | if (in.readableBytes() < 3) { 47 | return; 48 | } 49 | final int startOffset = in.readerOffset(); 50 | final byte version = in.getByte(startOffset); 51 | if (version != 1) { 52 | throw new DecoderException("unsupported subnegotiation version: " + version + " (expected: 1)"); 53 | } 54 | 55 | final int usernameLength = in.getUnsignedByte(startOffset + 1); 56 | final int passwordLength = in.getUnsignedByte(startOffset + 2 + usernameLength); 57 | final int totalLength = usernameLength + passwordLength + 3; 58 | if (in.readableBytes() < totalLength) { 59 | return; 60 | } 61 | in.skipReadableBytes(2); 62 | String username = in.readCharSequence(usernameLength, StandardCharsets.US_ASCII).toString(); 63 | in.skipReadableBytes(1); 64 | String password = in.readCharSequence(passwordLength, StandardCharsets.US_ASCII).toString(); 65 | ctx.fireChannelRead(new DefaultSocks5PasswordAuthRequest(username, password)); 66 | 67 | state = State.SUCCESS; 68 | } 69 | case SUCCESS: { 70 | int readableBytes = actualReadableBytes(); 71 | if (readableBytes > 0) { 72 | ctx.fireChannelRead(in.readSplit(readableBytes)); 73 | } 74 | break; 75 | } 76 | case FAILURE: { 77 | in.skipReadableBytes(actualReadableBytes()); 78 | break; 79 | } 80 | } 81 | } catch (Exception e) { 82 | fail(ctx, e); 83 | } 84 | } 85 | 86 | private void fail(ChannelHandlerContext ctx, Exception cause) { 87 | if (!(cause instanceof DecoderException)) { 88 | cause = new DecoderException(cause); 89 | } 90 | 91 | state = State.FAILURE; 92 | 93 | Socks5Message m = new DefaultSocks5PasswordAuthRequest("", ""); 94 | m.setDecoderResult(DecoderResult.failure(cause)); 95 | ctx.fireChannelRead(m); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/DefaultSocks5CommandRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.handler.codec.DecoderResult; 19 | import io.netty5.util.NetUtil; 20 | import io.netty5.util.internal.StringUtil; 21 | 22 | import java.net.IDN; 23 | 24 | import static java.util.Objects.requireNonNull; 25 | 26 | /** 27 | * The default {@link Socks5CommandRequest}. 28 | */ 29 | public final class DefaultSocks5CommandRequest extends AbstractSocks5Message implements Socks5CommandRequest { 30 | 31 | private final Socks5CommandType type; 32 | private final Socks5AddressType dstAddrType; 33 | private final String dstAddr; 34 | private final int dstPort; 35 | 36 | public DefaultSocks5CommandRequest( 37 | Socks5CommandType type, Socks5AddressType dstAddrType, String dstAddr, int dstPort) { 38 | requireNonNull(type, "type"); 39 | requireNonNull(dstAddrType, "dstAddrType"); 40 | requireNonNull(dstAddr, "dstAddr"); 41 | 42 | if (dstAddrType == Socks5AddressType.IPv4) { 43 | if (!NetUtil.isValidIpV4Address(dstAddr)) { 44 | throw new IllegalArgumentException("dstAddr: " + dstAddr + " (expected: a valid IPv4 address)"); 45 | } 46 | } else if (dstAddrType == Socks5AddressType.DOMAIN) { 47 | dstAddr = IDN.toASCII(dstAddr); 48 | if (dstAddr.length() > 255) { 49 | throw new IllegalArgumentException("dstAddr: " + dstAddr + " (expected: less than 256 chars)"); 50 | } 51 | } else if (dstAddrType == Socks5AddressType.IPv6) { 52 | if (!NetUtil.isValidIpV6Address(dstAddr)) { 53 | throw new IllegalArgumentException("dstAddr: " + dstAddr + " (expected: a valid IPv6 address"); 54 | } 55 | } 56 | 57 | if (dstPort < 0 || dstPort > 65535) { 58 | throw new IllegalArgumentException("dstPort: " + dstPort + " (expected: 0~65535)"); 59 | } 60 | 61 | this.type = type; 62 | this.dstAddrType = dstAddrType; 63 | this.dstAddr = dstAddr; 64 | this.dstPort = dstPort; 65 | } 66 | 67 | @Override 68 | public Socks5CommandType type() { 69 | return type; 70 | } 71 | 72 | @Override 73 | public Socks5AddressType dstAddrType() { 74 | return dstAddrType; 75 | } 76 | 77 | @Override 78 | public String dstAddr() { 79 | return dstAddr; 80 | } 81 | 82 | @Override 83 | public int dstPort() { 84 | return dstPort; 85 | } 86 | 87 | @Override 88 | public String toString() { 89 | StringBuilder buf = new StringBuilder(128); 90 | buf.append(StringUtil.simpleClassName(this)); 91 | 92 | DecoderResult decoderResult = decoderResult(); 93 | if (!decoderResult.isSuccess()) { 94 | buf.append("(decoderResult: "); 95 | buf.append(decoderResult); 96 | buf.append(", type: "); 97 | } else { 98 | buf.append("(type: "); 99 | } 100 | buf.append(type()); 101 | buf.append(", dstAddrType: "); 102 | buf.append(dstAddrType()); 103 | buf.append(", dstAddr: "); 104 | buf.append(dstAddr()); 105 | buf.append(", dstPort: "); 106 | buf.append(dstPort()); 107 | buf.append(')'); 108 | 109 | return buf.toString(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5CommandStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import static java.util.Objects.requireNonNull; 19 | 20 | /** 21 | * The status of {@link Socks5CommandResponse}. 22 | */ 23 | public class Socks5CommandStatus implements Comparable { 24 | 25 | public static final Socks5CommandStatus SUCCESS = new Socks5CommandStatus(0x00, "SUCCESS"); 26 | public static final Socks5CommandStatus FAILURE = new Socks5CommandStatus(0x01, "FAILURE"); 27 | public static final Socks5CommandStatus FORBIDDEN = new Socks5CommandStatus(0x02, "FORBIDDEN"); 28 | public static final Socks5CommandStatus NETWORK_UNREACHABLE = new Socks5CommandStatus(0x03, "NETWORK_UNREACHABLE"); 29 | public static final Socks5CommandStatus HOST_UNREACHABLE = new Socks5CommandStatus(0x04, "HOST_UNREACHABLE"); 30 | public static final Socks5CommandStatus CONNECTION_REFUSED = new Socks5CommandStatus(0x05, "CONNECTION_REFUSED"); 31 | public static final Socks5CommandStatus TTL_EXPIRED = new Socks5CommandStatus(0x06, "TTL_EXPIRED"); 32 | public static final Socks5CommandStatus COMMAND_UNSUPPORTED = new Socks5CommandStatus(0x07, "COMMAND_UNSUPPORTED"); 33 | public static final Socks5CommandStatus ADDRESS_UNSUPPORTED = new Socks5CommandStatus(0x08, "ADDRESS_UNSUPPORTED"); 34 | 35 | public static Socks5CommandStatus valueOf(byte b) { 36 | switch (b) { 37 | case 0x00: 38 | return SUCCESS; 39 | case 0x01: 40 | return FAILURE; 41 | case 0x02: 42 | return FORBIDDEN; 43 | case 0x03: 44 | return NETWORK_UNREACHABLE; 45 | case 0x04: 46 | return HOST_UNREACHABLE; 47 | case 0x05: 48 | return CONNECTION_REFUSED; 49 | case 0x06: 50 | return TTL_EXPIRED; 51 | case 0x07: 52 | return COMMAND_UNSUPPORTED; 53 | case 0x08: 54 | return ADDRESS_UNSUPPORTED; 55 | } 56 | 57 | return new Socks5CommandStatus(b); 58 | } 59 | 60 | private final byte byteValue; 61 | private final String name; 62 | private String text; 63 | 64 | public Socks5CommandStatus(int byteValue) { 65 | this(byteValue, "UNKNOWN"); 66 | } 67 | 68 | public Socks5CommandStatus(int byteValue, String name) { 69 | requireNonNull(name, "name"); 70 | 71 | this.byteValue = (byte) byteValue; 72 | this.name = name; 73 | } 74 | 75 | public byte byteValue() { 76 | return byteValue; 77 | } 78 | 79 | public boolean isSuccess() { 80 | return byteValue == 0; 81 | } 82 | 83 | @Override 84 | public int hashCode() { 85 | return byteValue; 86 | } 87 | 88 | @Override 89 | public boolean equals(Object obj) { 90 | if (!(obj instanceof Socks5CommandStatus)) { 91 | return false; 92 | } 93 | 94 | return byteValue == ((Socks5CommandStatus) obj).byteValue; 95 | } 96 | 97 | @Override 98 | public int compareTo(Socks5CommandStatus o) { 99 | return byteValue - o.byteValue; 100 | } 101 | 102 | @Override 103 | public String toString() { 104 | String text = this.text; 105 | if (text == null) { 106 | this.text = text = name + '(' + (byteValue & 0xFF) + ')'; 107 | } 108 | return text; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /codec-socks/src/main/java/io/netty/contrib/handler/codec/socksx/v5/Socks5ServerEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.netty.contrib.handler.codec.socksx.v5; 17 | 18 | import io.netty5.buffer.Buffer; 19 | import io.netty5.channel.ChannelHandlerContext; 20 | import io.netty5.handler.codec.EncoderException; 21 | import io.netty5.handler.codec.MessageToByteEncoder; 22 | import io.netty5.util.internal.StringUtil; 23 | 24 | import static java.util.Objects.requireNonNull; 25 | 26 | /** 27 | * Encodes a server-side {@link Socks5Message} into a {@link Buffer}. 28 | */ 29 | public class Socks5ServerEncoder extends MessageToByteEncoder { 30 | 31 | public static final Socks5ServerEncoder DEFAULT = new Socks5ServerEncoder(Socks5AddressEncoder.DEFAULT); 32 | 33 | private final Socks5AddressEncoder addressEncoder; 34 | 35 | /** 36 | * Creates a new instance with the default {@link Socks5AddressEncoder}. 37 | */ 38 | protected Socks5ServerEncoder() { 39 | this(Socks5AddressEncoder.DEFAULT); 40 | } 41 | 42 | @Override 43 | protected Buffer allocateBuffer(ChannelHandlerContext ctx, Socks5Message msg) { 44 | return ctx.bufferAllocator().allocate(256); 45 | } 46 | 47 | /** 48 | * Creates a new instance with the specified {@link Socks5AddressEncoder}. 49 | */ 50 | public Socks5ServerEncoder(Socks5AddressEncoder addressEncoder) { 51 | requireNonNull(addressEncoder, "addressEncoder"); 52 | 53 | this.addressEncoder = addressEncoder; 54 | } 55 | 56 | /** 57 | * Returns the {@link Socks5AddressEncoder} of this encoder. 58 | */ 59 | protected final Socks5AddressEncoder addressEncoder() { 60 | return addressEncoder; 61 | } 62 | 63 | @Override 64 | protected void encode(ChannelHandlerContext ctx, Socks5Message msg, Buffer out) throws Exception { 65 | if (msg instanceof Socks5InitialResponse) { 66 | encodeAuthMethodResponse((Socks5InitialResponse) msg, out); 67 | } else if (msg instanceof Socks5PasswordAuthResponse) { 68 | encodePasswordAuthResponse((Socks5PasswordAuthResponse) msg, out); 69 | } else if (msg instanceof Socks5CommandResponse) { 70 | encodeCommandResponse((Socks5CommandResponse) msg, out); 71 | } else { 72 | throw new EncoderException("unsupported message type: " + StringUtil.simpleClassName(msg)); 73 | } 74 | } 75 | 76 | private static void encodeAuthMethodResponse(Socks5InitialResponse msg, Buffer out) { 77 | out.writeByte(msg.version().byteValue()); 78 | out.writeByte(msg.authMethod().byteValue()); 79 | } 80 | 81 | private static void encodePasswordAuthResponse(Socks5PasswordAuthResponse msg, Buffer out) { 82 | out.writeByte((byte) 0x01); 83 | out.writeByte(msg.status().byteValue()); 84 | } 85 | 86 | private void encodeCommandResponse(Socks5CommandResponse msg, Buffer out) throws Exception { 87 | out.writeByte(msg.version().byteValue()); 88 | out.writeByte(msg.status().byteValue()); 89 | out.writeByte((byte) 0x00); 90 | 91 | final Socks5AddressType bndAddrType = msg.bndAddrType(); 92 | out.writeByte(bndAddrType.byteValue()); 93 | addressEncoder.encodeAddress(bndAddrType, msg.bndAddr(), out); 94 | 95 | out.writeShort((short) msg.bndPort()); 96 | } 97 | 98 | @Override 99 | public boolean isSharable() { 100 | return true; 101 | } 102 | } 103 | --------------------------------------------------------------------------------