basic support for socks5 codec
This commit is contained in:
parent
ef26ffe9d8
commit
5d2b41c094
43
codec-socks/pom.xml
Normal file
43
codec-socks/pom.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2012 The Netty Project
|
||||
~
|
||||
~ The Netty Project licenses this file to you under the Apache License,
|
||||
~ version 2.0 (the "License"); you may not use this file except in compliance
|
||||
~ with the License. You may obtain a copy of the License at:
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
~ License for the specific language governing permissions and limitations
|
||||
~ under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-parent</artifactId>
|
||||
<version>4.0.0.Alpha8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>netty-codec-socks</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Netty/Codec/Socks</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-codec</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
/**
|
||||
* An socks auth request.
|
||||
*
|
||||
* @see SocksAuthResponse
|
||||
* @see SocksAuthRequestDecoder
|
||||
*/
|
||||
public final class SocksAuthRequest extends SocksRequest {
|
||||
private static final CharsetEncoder asciiEncoder = CharsetUtil.getEncoder(CharsetUtil.US_ASCII);
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param username
|
||||
* @param password
|
||||
* @throws NullPointerException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public SocksAuthRequest(String username, String password) {
|
||||
super(SocksRequestType.AUTH);
|
||||
if (username == null) {
|
||||
throw new NullPointerException("username");
|
||||
}
|
||||
if (password == null) {
|
||||
throw new NullPointerException("username");
|
||||
}
|
||||
if (!asciiEncoder.canEncode(username) || !asciiEncoder.canEncode(password)) {
|
||||
throw new IllegalArgumentException(" username: " + username + " or password: " + password +
|
||||
" values should be in pure ascii");
|
||||
}
|
||||
if (username.length() > 255) {
|
||||
throw new IllegalArgumentException(username + " exceeds 255 char limit");
|
||||
}
|
||||
if (password.length() > 255) {
|
||||
throw new IllegalArgumentException(password + " exceeds 255 char limit");
|
||||
}
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns username that needs to be authenticated
|
||||
*
|
||||
* @return username that needs to be authenticated
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns password that needs to be validated
|
||||
*
|
||||
* @return password that needs to be validated
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(getProtocolVersion().getByteValue());
|
||||
byteBuf.writeByte(username.length());
|
||||
byteBuf.writeBytes(username.getBytes(CharsetUtil.US_ASCII));
|
||||
byteBuf.writeByte(password.length());
|
||||
byteBuf.writeBytes(password.getBytes(CharsetUtil.US_ASCII));
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksAuthRequest}.
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksAuthRequestDecoder extends ReplayingDecoder<SocksRequest, SocksAuthRequestDecoder.State> {
|
||||
private static final String name = "SOCKS_AUTH_REQUEST_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksMessage.ProtocolVersion version;
|
||||
private int fieldLength;
|
||||
private String username;
|
||||
private String password;
|
||||
private SocksRequest msg = SocksCommonUtils.UNKNOWN_SOCKS_REQUEST;
|
||||
|
||||
public SocksAuthRequestDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocksRequest decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksMessage.ProtocolVersion.fromByte((byte) byteBuf.readByte());
|
||||
if (version != SocksMessage.ProtocolVersion.SOCKS5) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_USERNAME);
|
||||
}
|
||||
case READ_USERNAME: {
|
||||
fieldLength = byteBuf.readByte();
|
||||
username = byteBuf.readBytes(fieldLength).toString(CharsetUtil.US_ASCII);
|
||||
checkpoint(State.READ_PASSWORD);
|
||||
}
|
||||
case READ_PASSWORD: {
|
||||
fieldLength = byteBuf.readByte();
|
||||
password = byteBuf.readBytes(fieldLength).toString(CharsetUtil.US_ASCII);
|
||||
msg = new SocksAuthRequest(username, password);
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
return msg;
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_USERNAME,
|
||||
READ_PASSWORD
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An socks auth response.
|
||||
*
|
||||
* @see SocksAuthRequest
|
||||
* @see SocksAuthResponseDecoder
|
||||
*/
|
||||
public final class SocksAuthResponse extends SocksResponse {
|
||||
|
||||
private final AuthStatus authStatus;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param authStatus
|
||||
* @throws NullPointerException
|
||||
*/
|
||||
|
||||
public SocksAuthResponse(AuthStatus authStatus) {
|
||||
super(SocksResponseType.AUTH);
|
||||
if (authStatus == null) {
|
||||
throw new NullPointerException("authStatus");
|
||||
}
|
||||
this.authStatus = authStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AuthStatus} of this {@link SocksAuthResponse}
|
||||
*
|
||||
* @return The {@link AuthStatus} of this {@link SocksAuthResponse}
|
||||
*/
|
||||
public AuthStatus getAuthStatus() {
|
||||
return authStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(getProtocolVersion().getByteValue());
|
||||
byteBuf.writeByte(authStatus.getByteValue());
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksAuthResponse}.
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksAuthResponseDecoder extends ReplayingDecoder<SocksResponse, SocksAuthResponseDecoder.State> {
|
||||
private static final String name = "SOCKS_AUTH_RESPONSE_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksMessage.ProtocolVersion version;
|
||||
private SocksMessage.AuthStatus authStatus;
|
||||
private SocksResponse msg = SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE;
|
||||
|
||||
public SocksAuthResponseDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocksResponse decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksMessage.ProtocolVersion.fromByte(byteBuf.readByte());
|
||||
if (version != SocksMessage.ProtocolVersion.SOCKS5) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_AUTH_RESPONSE);
|
||||
}
|
||||
case READ_AUTH_RESPONSE: {
|
||||
authStatus = SocksMessage.AuthStatus.fromByte(byteBuf.readByte());
|
||||
msg = new SocksAuthResponse(authStatus);
|
||||
}
|
||||
}
|
||||
channelHandlerContext.pipeline().remove(this);
|
||||
return msg;
|
||||
}
|
||||
|
||||
public enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_AUTH_RESPONSE
|
||||
}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
|
||||
import java.net.IDN;
|
||||
|
||||
/**
|
||||
* An socks cmd request.
|
||||
*
|
||||
* @see SocksCmdResponse
|
||||
* @see SocksCmdRequestDecoder
|
||||
*/
|
||||
public final class SocksCmdRequest extends SocksRequest {
|
||||
private final CmdType cmdType;
|
||||
private final AddressType addressType;
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cmdType
|
||||
* @param addressType
|
||||
* @param host
|
||||
* @param port
|
||||
* @throws NullPointerException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public SocksCmdRequest(CmdType cmdType, AddressType addressType, String host, int port) {
|
||||
super(SocksRequestType.CMD);
|
||||
if (cmdType == null) {
|
||||
throw new NullPointerException("cmdType");
|
||||
}
|
||||
if (addressType == null) {
|
||||
throw new NullPointerException("addressType");
|
||||
}
|
||||
if (host == null) {
|
||||
throw new NullPointerException("host");
|
||||
}
|
||||
switch (addressType) {
|
||||
case IPv4:
|
||||
if (!IPAddressUtil.isIPv4LiteralAddress(host)) {
|
||||
throw new IllegalArgumentException(host + " is not a valid IPv4 address");
|
||||
}
|
||||
break;
|
||||
case DOMAIN:
|
||||
if (IDN.toASCII(host).length() > 255) {
|
||||
throw new IllegalArgumentException(host + " IDN: " + IDN.toASCII(host) + " exceeds 255 char limit");
|
||||
}
|
||||
break;
|
||||
case IPv6:
|
||||
if (!IPAddressUtil.isIPv6LiteralAddress(host)) {
|
||||
throw new IllegalArgumentException(host + " is not a valid IPv6 address");
|
||||
}
|
||||
break;
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
if ((port < 0) && (port >= 65535)) {
|
||||
throw new IllegalArgumentException(port + " is not in bounds 0 < x < 65536");
|
||||
}
|
||||
this.cmdType = cmdType;
|
||||
this.addressType = addressType;
|
||||
this.host = IDN.toASCII(host);
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link CmdType} of this {@link SocksCmdRequest}
|
||||
*
|
||||
* @return The {@link CmdType} of this {@link SocksCmdRequest}
|
||||
*/
|
||||
public CmdType getCmdType() {
|
||||
return cmdType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AddressType} of this {@link SocksCmdRequest}
|
||||
*
|
||||
* @return The {@link AddressType} of this {@link SocksCmdRequest}
|
||||
*/
|
||||
public AddressType getAddressType() {
|
||||
return addressType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns host that is used as a parameter in {@link CmdType}
|
||||
*
|
||||
* @return host that is used as a parameter in {@link CmdType}
|
||||
*/
|
||||
public String getHost() {
|
||||
return IDN.toUnicode(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns port that is used as a parameter in {@link CmdType}
|
||||
*
|
||||
* @return port that is used as a parameter in {@link CmdType}
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(getProtocolVersion().getByteValue());
|
||||
byteBuf.writeByte(cmdType.getByteValue());
|
||||
byteBuf.writeByte(0x00);
|
||||
byteBuf.writeByte(addressType.getByteValue());
|
||||
switch (addressType) {
|
||||
case IPv4: {
|
||||
byteBuf.writeBytes(IPAddressUtil.textToNumericFormatV4(host));
|
||||
byteBuf.writeShort(port);
|
||||
break;
|
||||
}
|
||||
|
||||
case DOMAIN: {
|
||||
byteBuf.writeByte(host.length());
|
||||
byteBuf.writeBytes(host.getBytes(CharsetUtil.US_ASCII));
|
||||
byteBuf.writeShort(port);
|
||||
break;
|
||||
}
|
||||
|
||||
case IPv6: {
|
||||
byteBuf.writeBytes(IPAddressUtil.textToNumericFormatV6(host));
|
||||
byteBuf.writeShort(port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksCmdRequest}.
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksCmdRequestDecoder extends ReplayingDecoder<SocksRequest, SocksCmdRequestDecoder.State> {
|
||||
private static final String name = "SOCKS_CMD_REQUEST_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksMessage.ProtocolVersion version;
|
||||
private int fieldLength;
|
||||
private SocksMessage.CmdType cmdType;
|
||||
private SocksMessage.AddressType addressType;
|
||||
private byte reserved;
|
||||
private String host;
|
||||
private int port;
|
||||
private SocksRequest msg = SocksCommonUtils.UNKNOWN_SOCKS_REQUEST;
|
||||
|
||||
public SocksCmdRequestDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocksRequest decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
|
||||
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksMessage.ProtocolVersion.fromByte(byteBuf.readByte());
|
||||
if (version != SocksMessage.ProtocolVersion.SOCKS5) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_CMD_HEADER);
|
||||
}
|
||||
case READ_CMD_HEADER: {
|
||||
cmdType = SocksMessage.CmdType.fromByte(byteBuf.readByte());
|
||||
reserved = byteBuf.readByte();
|
||||
addressType = SocksMessage.AddressType.fromByte(byteBuf.readByte());
|
||||
checkpoint(State.READ_CMD_ADDRESS);
|
||||
}
|
||||
case READ_CMD_ADDRESS: {
|
||||
switch (addressType) {
|
||||
case IPv4: {
|
||||
host = SocksCommonUtils.intToIp(byteBuf.readInt());
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksCmdRequest(cmdType, addressType, host, port);
|
||||
break;
|
||||
}
|
||||
case DOMAIN: {
|
||||
fieldLength = byteBuf.readByte();
|
||||
host = byteBuf.readBytes(fieldLength).toString(CharsetUtil.US_ASCII);
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksCmdRequest(cmdType, addressType, host, port);
|
||||
break;
|
||||
}
|
||||
case IPv6: {
|
||||
host = SocksCommonUtils.ipv6toStr(byteBuf.readBytes(16).array());
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksCmdRequest(cmdType, addressType, host, port);
|
||||
break;
|
||||
}
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
return msg;
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_CMD_HEADER,
|
||||
READ_CMD_ADDRESS
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An socks cmd response.
|
||||
*
|
||||
* @see SocksCmdRequest
|
||||
* @see SocksCmdResponseDecoder
|
||||
*/
|
||||
public final class SocksCmdResponse extends SocksResponse {
|
||||
private final CmdStatus cmdStatus;
|
||||
|
||||
private final AddressType addressType;
|
||||
// All arrays are initialized on construction time to 0/false/null remove array Initialization
|
||||
private static final byte[] IPv4_HOSTNAME_ZEROED = {0x00, 0x00, 0x00, 0x00};
|
||||
private static final byte[] IPv6_HOSTNAME_ZEROED = {0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cmdStatus
|
||||
* @param addressType
|
||||
* @throws NullPointerException
|
||||
*/
|
||||
public SocksCmdResponse(CmdStatus cmdStatus, AddressType addressType) {
|
||||
super(SocksResponseType.CMD);
|
||||
if (cmdStatus == null) {
|
||||
throw new NullPointerException("cmdStatus");
|
||||
}
|
||||
if (addressType == null) {
|
||||
throw new NullPointerException("addressType");
|
||||
}
|
||||
this.cmdStatus = cmdStatus;
|
||||
this.addressType = addressType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link CmdStatus} of this {@link SocksCmdResponse}
|
||||
*
|
||||
* @return The {@link CmdStatus} of this {@link SocksCmdResponse}
|
||||
*/
|
||||
public CmdStatus getCmdStatus() {
|
||||
return cmdStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AddressType} of this {@link SocksCmdResponse}
|
||||
*
|
||||
* @return The {@link AddressType} of this {@link SocksCmdResponse}
|
||||
*/
|
||||
public AddressType getAddressType() {
|
||||
return addressType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(getProtocolVersion().getByteValue());
|
||||
byteBuf.writeByte(cmdStatus.getByteValue());
|
||||
byteBuf.writeByte(0x00);
|
||||
byteBuf.writeByte(addressType.getByteValue());
|
||||
switch (addressType) {
|
||||
case IPv4: {
|
||||
byteBuf.writeBytes(IPv4_HOSTNAME_ZEROED);
|
||||
byteBuf.writeShort(0);
|
||||
break;
|
||||
}
|
||||
case DOMAIN: {
|
||||
byteBuf.writeByte(1); // domain length
|
||||
byteBuf.writeByte(0); // domain value
|
||||
byteBuf.writeShort(0); // port value
|
||||
break;
|
||||
}
|
||||
case IPv6: {
|
||||
byteBuf.writeBytes(IPv6_HOSTNAME_ZEROED);
|
||||
byteBuf.writeShort(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksCmdResponse}.
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksCmdResponseDecoder extends ReplayingDecoder<SocksResponse, SocksCmdResponseDecoder.State> {
|
||||
private static final String name = "SOCKS_CMD_RESPONSE_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksMessage.ProtocolVersion version;
|
||||
private int fieldLength;
|
||||
private SocksMessage.CmdStatus cmdStatus;
|
||||
private SocksMessage.AddressType addressType;
|
||||
private byte reserved;
|
||||
private String host;
|
||||
private int port;
|
||||
private SocksResponse msg = SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE;
|
||||
|
||||
|
||||
public SocksCmdResponseDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocksResponse decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
|
||||
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksMessage.ProtocolVersion.fromByte(byteBuf.readByte());
|
||||
if (version != SocksMessage.ProtocolVersion.SOCKS5) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_CMD_HEADER);
|
||||
}
|
||||
case READ_CMD_HEADER: {
|
||||
cmdStatus = SocksMessage.CmdStatus.fromByte(byteBuf.readByte());
|
||||
reserved = byteBuf.readByte();
|
||||
addressType = SocksMessage.AddressType.fromByte(byteBuf.readByte());
|
||||
checkpoint(State.READ_CMD_ADDRESS);
|
||||
}
|
||||
case READ_CMD_ADDRESS: {
|
||||
switch (addressType) {
|
||||
case IPv4: {
|
||||
host = SocksCommonUtils.intToIp(byteBuf.readInt());
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksCmdResponse(cmdStatus, addressType);
|
||||
break;
|
||||
}
|
||||
case DOMAIN: {
|
||||
fieldLength = byteBuf.readByte();
|
||||
host = byteBuf.readBytes(fieldLength).toString(CharsetUtil.US_ASCII);
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksCmdResponse(cmdStatus, addressType);
|
||||
break;
|
||||
}
|
||||
case IPv6: {
|
||||
host = SocksCommonUtils.ipv6toStr(byteBuf.readBytes(16).array());
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksCmdResponse(cmdStatus, addressType);
|
||||
break;
|
||||
}
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
return msg;
|
||||
}
|
||||
|
||||
public enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_CMD_HEADER,
|
||||
READ_CMD_ADDRESS
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
final class SocksCommonUtils {
|
||||
public static final SocksRequest UNKNOWN_SOCKS_REQUEST = new UnknownSocksRequest();
|
||||
public static final SocksResponse UNKNOWN_SOCKS_RESPONSE = new UnknownSocksResponse();
|
||||
|
||||
private static final int SECOND_ADDRESS_OCTET_SHIFT = 16;
|
||||
private static final int FIRST_ADDRESS_OCTET_SHIFT = 24;
|
||||
private static final int THIRD_ADDRESS_OCTET_SHIFT = 8;
|
||||
private static final int XOR_DEFAULT_VALUE = 0xff;
|
||||
|
||||
/**
|
||||
* A constructor to stop this class being constructed.
|
||||
*/
|
||||
private SocksCommonUtils() {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public static String intToIp(int i) {
|
||||
return new StringBuilder().append((i >> FIRST_ADDRESS_OCTET_SHIFT) & XOR_DEFAULT_VALUE).append(".")
|
||||
.append((i >> SECOND_ADDRESS_OCTET_SHIFT) & XOR_DEFAULT_VALUE).append(".")
|
||||
.append((i >> THIRD_ADDRESS_OCTET_SHIFT) & XOR_DEFAULT_VALUE).append(".")
|
||||
.append(i & XOR_DEFAULT_VALUE).toString();
|
||||
}
|
||||
|
||||
private static final char[] ipv6conseqZeroFiller = {':', ':'};
|
||||
private static final char ipv6hextetSeparator = ':';
|
||||
|
||||
/*
|
||||
* Convert numeric IPv6 to compressed format, where
|
||||
* the longest sequence of 0's (with 2 or more 0's) is replaced with "::"
|
||||
*/
|
||||
public static String ipv6toCompressedForm(byte[] src) {
|
||||
assert src.length == 16;
|
||||
//Find the longest sequence of 0's
|
||||
//start of compressed region (hextet index)
|
||||
int cmprHextet = -1;
|
||||
//length of compressed region
|
||||
int cmprSize = 0;
|
||||
for (int hextet = 0; hextet < 8;) {
|
||||
int curByte = hextet * 2;
|
||||
int size = 0;
|
||||
while (curByte < src.length && src[curByte] == 0
|
||||
&& src[curByte + 1] == 0) {
|
||||
curByte += 2;
|
||||
size++;
|
||||
}
|
||||
if (size > cmprSize) {
|
||||
cmprHextet = hextet;
|
||||
cmprSize = size;
|
||||
}
|
||||
hextet = (curByte / 2) + 1;
|
||||
}
|
||||
if (cmprHextet == -1 || cmprSize < 2) {
|
||||
//No compression can be applied
|
||||
return ipv6toStr(src);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(39);
|
||||
ipv6toStr(sb, src, 0, cmprHextet);
|
||||
sb.append(ipv6conseqZeroFiller);
|
||||
ipv6toStr(sb, src, cmprHextet + cmprSize, 8);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert numeric IPv6 to standard (non-compressed) format.
|
||||
*
|
||||
* Borrowed from Inet6Address.java #numericToTextFormat(byte[])
|
||||
* Changed StringBuffer -> StringBuilder and ":" -> ':' for performance.
|
||||
*/
|
||||
public static String ipv6toStr(byte[] src) {
|
||||
assert src.length == 16;
|
||||
StringBuilder sb = new StringBuilder(39);
|
||||
ipv6toStr(sb, src, 0, 8);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void ipv6toStr(StringBuilder sb, byte[] src,
|
||||
int fromHextet, int toHextet) {
|
||||
for (int i = fromHextet; i < toHextet; i++) {
|
||||
sb.append(Integer.toHexString(((src[i << 1] << 8) & 0xff00)
|
||||
| (src[(i << 1) + 1] & 0xff)));
|
||||
if (i < toHextet - 1) {
|
||||
sb.append(ipv6hextetSeparator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An socks init request.
|
||||
*
|
||||
* @see SocksInitResponse
|
||||
* @see SocksInitRequestDecoder
|
||||
*/
|
||||
public final class SocksInitRequest extends SocksRequest {
|
||||
private final List<AuthScheme> authSchemes;
|
||||
|
||||
public SocksInitRequest(List<AuthScheme> authSchemes) {
|
||||
super(SocksRequestType.INIT);
|
||||
if (authSchemes == null) {
|
||||
throw new NullPointerException("authSchemes");
|
||||
}
|
||||
this.authSchemes = authSchemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the List<{@link AuthScheme}> of this {@link SocksInitRequest}
|
||||
*
|
||||
* @return The List<{@link AuthScheme}> of this {@link SocksInitRequest}
|
||||
*/
|
||||
public List<AuthScheme> getAuthSchemes() {
|
||||
return Collections.unmodifiableList(authSchemes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(getProtocolVersion().getByteValue());
|
||||
byteBuf.writeByte(authSchemes.size());
|
||||
for (AuthScheme authScheme : authSchemes) {
|
||||
byteBuf.writeByte(authScheme.getByteValue());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksInitRequest}.
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksInitRequestDecoder extends ReplayingDecoder<SocksRequest, SocksInitRequestDecoder.State> {
|
||||
private static final String name = "SOCKS_INIT_REQUEST_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private final List<SocksMessage.AuthScheme> authSchemes = new ArrayList<SocksMessage.AuthScheme>();
|
||||
private SocksMessage.ProtocolVersion version;
|
||||
private byte authSchemeNum;
|
||||
private SocksRequest msg = SocksCommonUtils.UNKNOWN_SOCKS_REQUEST;
|
||||
|
||||
public SocksInitRequestDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocksRequest decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksMessage.ProtocolVersion.fromByte(byteBuf.readByte());
|
||||
if (version != SocksMessage.ProtocolVersion.SOCKS5) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_AUTH_SCHEMES);
|
||||
}
|
||||
case READ_AUTH_SCHEMES: {
|
||||
authSchemes.clear();
|
||||
authSchemeNum = byteBuf.readByte();
|
||||
for (int i = 0; i < authSchemeNum; i++) {
|
||||
authSchemes.add(SocksMessage.AuthScheme.fromByte(byteBuf.readByte()));
|
||||
}
|
||||
msg = new SocksInitRequest(authSchemes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
return msg;
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_AUTH_SCHEMES
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An socks init response.
|
||||
*
|
||||
* @see SocksInitRequest
|
||||
* @see SocksInitResponseDecoder
|
||||
*/
|
||||
public final class SocksInitResponse extends SocksResponse {
|
||||
private final AuthScheme authScheme;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param authScheme
|
||||
* @throws NullPointerException
|
||||
*/
|
||||
public SocksInitResponse(AuthScheme authScheme) {
|
||||
super(SocksResponseType.INIT);
|
||||
if (authScheme == null) {
|
||||
throw new NullPointerException("authScheme");
|
||||
}
|
||||
this.authScheme = authScheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AuthScheme} of this {@link SocksInitResponse}
|
||||
*
|
||||
* @return The {@link AuthScheme} of this {@link SocksInitResponse}
|
||||
*/
|
||||
public AuthScheme getAuthScheme() {
|
||||
return authScheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(getProtocolVersion().getByteValue());
|
||||
byteBuf.writeByte(authScheme.getByteValue());
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksInitResponse}.
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksInitResponseDecoder extends ReplayingDecoder<SocksResponse, SocksInitResponseDecoder.State> {
|
||||
private static final String name = "SOCKS_INIT_RESPONSE_DECODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private SocksMessage.ProtocolVersion version;
|
||||
private SocksMessage.AuthScheme authScheme;
|
||||
|
||||
private SocksResponse msg = SocksCommonUtils.UNKNOWN_SOCKS_RESPONSE;
|
||||
|
||||
public SocksInitResponseDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocksResponse decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksMessage.ProtocolVersion.fromByte(byteBuf.readByte());
|
||||
if (version != SocksMessage.ProtocolVersion.SOCKS5) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_PREFFERED_AUTH_TYPE);
|
||||
}
|
||||
case READ_PREFFERED_AUTH_TYPE: {
|
||||
authScheme = SocksMessage.AuthScheme.fromByte(byteBuf.readByte());
|
||||
msg = new SocksInitResponse(authScheme);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
return msg;
|
||||
}
|
||||
|
||||
public enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_PREFFERED_AUTH_TYPE
|
||||
}
|
||||
}
|
234
codec-socks/src/main/java/io/netty/codec/socks/SocksMessage.java
Normal file
234
codec-socks/src/main/java/io/netty/codec/socks/SocksMessage.java
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An abstract class that defines a SocksMessage, providing common properties for
|
||||
* {@link SocksRequest} and {@link SocksResponse}.
|
||||
*
|
||||
* @see SocksRequest
|
||||
* @see SocksResponse
|
||||
*/
|
||||
|
||||
public abstract class SocksMessage {
|
||||
private final MessageType messageType;
|
||||
private final ProtocolVersion protocolVersion = ProtocolVersion.SOCKS5;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param messageType
|
||||
* @throws NullPointerException
|
||||
*/
|
||||
public SocksMessage(MessageType messageType) {
|
||||
if (messageType == null) {
|
||||
throw new NullPointerException("messageType");
|
||||
}
|
||||
this.messageType = messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MessageType} of this {@link SocksMessage}
|
||||
*
|
||||
* @return The {@link MessageType} of this {@link SocksMessage}
|
||||
*/
|
||||
public MessageType getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public enum MessageType {
|
||||
REQUEST,
|
||||
RESPONSE,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
public enum AuthScheme {
|
||||
NO_AUTH((byte) 0x00),
|
||||
AUTH_GSSAPI((byte) 0x01),
|
||||
AUTH_PASSWORD((byte) 0x02),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
private AuthScheme(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static AuthScheme fromByte(byte b) {
|
||||
for (AuthScheme code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte getByteValue() {
|
||||
return this.b;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CmdType {
|
||||
CONNECT((byte) 0x01),
|
||||
BIND((byte) 0x02),
|
||||
UDP((byte) 0x03),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
private CmdType(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static CmdType fromByte(byte b) {
|
||||
for (CmdType code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte getByteValue() {
|
||||
return this.b;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AddressType {
|
||||
IPv4((byte) 0x01),
|
||||
DOMAIN((byte) 0x03),
|
||||
IPv6((byte) 0x04),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
private AddressType(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static AddressType fromByte(byte b) {
|
||||
for (AddressType code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte getByteValue() {
|
||||
return this.b;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AuthStatus {
|
||||
SUCCESS((byte) 0x00),
|
||||
FAILURE((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
private AuthStatus(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static AuthStatus fromByte(byte b) {
|
||||
for (AuthStatus code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
public byte getByteValue() {
|
||||
return this.b;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CmdStatus {
|
||||
SUCCESS((byte) 0x00),
|
||||
FAILURE((byte) 0x01),
|
||||
FORBIDDEN((byte) 0x02),
|
||||
NETWORK_UNREACHABLE((byte) 0x03),
|
||||
HOST_UNREACHABLE((byte) 0x04),
|
||||
REFUSED((byte) 0x05),
|
||||
TTL_EXPIRED((byte) 0x06),
|
||||
COMMAND_NOT_SUPPORTED((byte) 0x07),
|
||||
ADDRESS_NOT_SUPPORTED((byte) 0x08),
|
||||
UNASSIGNED((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
private CmdStatus(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static CmdStatus fromByte(byte b) {
|
||||
for (CmdStatus code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNASSIGNED;
|
||||
}
|
||||
|
||||
public byte getByteValue() {
|
||||
return this.b;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ProtocolVersion {
|
||||
SOCKS4a((byte) 0x04),
|
||||
SOCKS5((byte) 0x05),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
private ProtocolVersion(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static ProtocolVersion fromByte(byte b) {
|
||||
for (ProtocolVersion code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte getByteValue() {
|
||||
return this.b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ProtocolVersion} of this {@link SocksMessage}
|
||||
*
|
||||
* @return The {@link ProtocolVersion} of this {@link SocksMessage}
|
||||
*/
|
||||
public ProtocolVersion getProtocolVersion() {
|
||||
return protocolVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode socks message into its byte representation and write it into byteBuf
|
||||
*
|
||||
* @param byteBuf
|
||||
* @see ByteBuf
|
||||
*/
|
||||
public abstract void encodeAsByteBuf(ByteBuf byteBuf);
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
/**
|
||||
* Encodes an {@link SocksMessage} into a {@link ByteBuf}.
|
||||
* {@link MessageToByteEncoder} implementation.
|
||||
* Use this with {@link SocksInitRequest}, {@link SocksInitResponse}, {@link SocksAuthRequest},
|
||||
* {@link SocksAuthResponse}, {@link SocksCmdRequest} and {@link SocksCmdResponse}
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class SocksMessageEncoder extends MessageToByteEncoder<SocksMessage> {
|
||||
private static final String name = "SOCKS_MESSAGE_ENCODER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public SocksMessageEncoder() {
|
||||
super(SocksMessage.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ChannelHandlerContext ctx, SocksMessage msg, ByteBuf out) throws Exception {
|
||||
msg.encodeAsByteBuf(out);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
/**
|
||||
* An abstract class that defines a SocksRequest, providing common properties for
|
||||
* {@link SocksInitRequest}, {@link SocksAuthRequest}, {@link SocksCmdRequest} and {@link UnknownSocksRequest}.
|
||||
*
|
||||
* @see SocksInitRequest
|
||||
* @see SocksAuthRequest
|
||||
* @see SocksCmdRequest
|
||||
* @see UnknownSocksRequest
|
||||
*/
|
||||
public abstract class SocksRequest extends SocksMessage {
|
||||
private final SocksRequestType socksRequestType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param socksRequestType
|
||||
* @throws NullPointerException
|
||||
*/
|
||||
public SocksRequest(SocksRequestType socksRequestType) {
|
||||
super(MessageType.REQUEST);
|
||||
if (socksRequestType == null) {
|
||||
throw new NullPointerException("socksRequestType");
|
||||
}
|
||||
this.socksRequestType = socksRequestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns socks request type
|
||||
*
|
||||
* @return socks request type
|
||||
*/
|
||||
public SocksRequestType getSocksRequestType() {
|
||||
return socksRequestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of socks request
|
||||
*/
|
||||
public enum SocksRequestType {
|
||||
INIT,
|
||||
AUTH,
|
||||
CMD,
|
||||
UNKNOWN
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
/**
|
||||
* An abstract class that defines a SocksResponse, providing common properties for
|
||||
* {@link SocksInitResponse}, {@link SocksAuthResponse}, {@link SocksCmdResponse} and {@link UnknownSocksResponse}.
|
||||
*
|
||||
* @see SocksInitResponse
|
||||
* @see SocksAuthResponse
|
||||
* @see SocksCmdResponse
|
||||
* @see UnknownSocksResponse
|
||||
*/
|
||||
public abstract class SocksResponse extends SocksMessage {
|
||||
private final SocksResponseType socksResponseType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param socksResponseType
|
||||
* @throws NullPointerException
|
||||
*/
|
||||
public SocksResponse(SocksResponseType socksResponseType) {
|
||||
super(MessageType.RESPONSE);
|
||||
if (socksResponseType == null) {
|
||||
throw new NullPointerException("socksResponseType");
|
||||
}
|
||||
this.socksResponseType = socksResponseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns socks response type
|
||||
*
|
||||
* @return socks response type
|
||||
*/
|
||||
public SocksResponseType getSocksResponseType() {
|
||||
return socksResponseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of socks response
|
||||
*/
|
||||
public enum SocksResponseType {
|
||||
INIT,
|
||||
AUTH,
|
||||
CMD,
|
||||
UNKNOWN
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An unknown socks message.
|
||||
*
|
||||
* @see UnknownSocksRequest
|
||||
* @see UnknownSocksResponse
|
||||
*/
|
||||
public final class UnknownSocksMessage extends SocksMessage {
|
||||
|
||||
public UnknownSocksMessage() {
|
||||
super(MessageType.UNKNOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An unknown socks request.
|
||||
*
|
||||
* @see SocksInitRequestDecoder
|
||||
* @see SocksAuthRequestDecoder
|
||||
* @see SocksCmdRequestDecoder
|
||||
*/
|
||||
public final class UnknownSocksRequest extends SocksRequest {
|
||||
|
||||
public UnknownSocksRequest() {
|
||||
super(SocksRequestType.UNKNOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An unknown socks response.
|
||||
*
|
||||
* @see SocksInitResponseDecoder
|
||||
* @see SocksAuthResponseDecoder
|
||||
* @see SocksCmdResponseDecoder
|
||||
*/
|
||||
public final class UnknownSocksResponse extends SocksResponse {
|
||||
|
||||
public UnknownSocksResponse() {
|
||||
super(SocksResponseType.UNKNOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
// NOOP
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encoder, decoder and their related message types for Socks.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedByteChannel;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksAuthRequestDecoderTest {
|
||||
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SocksAuthRequestDecoderTest.class);
|
||||
@Test
|
||||
public void testAuthRequestDecoder() {
|
||||
String username = "test";
|
||||
String password = "test";
|
||||
SocksAuthRequest msg = new SocksAuthRequest(username, password);
|
||||
SocksAuthRequestDecoder decoder = new SocksAuthRequestDecoder();
|
||||
EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder);
|
||||
SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
msg = (SocksAuthRequest) embedder.readInbound();
|
||||
assertTrue(msg.getUsername().equals(username));
|
||||
assertTrue(msg.getUsername().equals(password));
|
||||
assertNull(embedder.readInbound());
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksAuthRequestTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksAuthRequest(null, "");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
try {
|
||||
new SocksAuthRequest("", null);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernameOrPasswordIsNotAscii() {
|
||||
try {
|
||||
new SocksAuthRequest("παράδειγμα.δοκιμή", "password");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
try {
|
||||
new SocksAuthRequest("username", "παράδειγμα.δοκιμή");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernameOrPasswordLengthIsLessThan255Chars() {
|
||||
try {
|
||||
new SocksAuthRequest(
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword",
|
||||
"password");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
try {
|
||||
new SocksAuthRequest("password",
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedByteChannel;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksAuthResponseDecoderTest {
|
||||
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SocksAuthResponseDecoderTest.class);
|
||||
private void testSocksAuthResponseDecoderWithDifferentParams(SocksMessage.AuthStatus authStatus){
|
||||
logger.debug("Testing SocksAuthResponseDecoder with authStatus: "+ authStatus);
|
||||
SocksAuthResponse msg = new SocksAuthResponse(authStatus);
|
||||
SocksAuthResponseDecoder decoder = new SocksAuthResponseDecoder();
|
||||
EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder);
|
||||
SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
msg = (SocksAuthResponse) embedder.readInbound();
|
||||
assertTrue(msg.getAuthStatus().equals(authStatus));
|
||||
assertNull(embedder.readInbound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSocksCmdResponseDecoder(){
|
||||
for (SocksMessage.AuthStatus authStatus: SocksMessage.AuthStatus.values()){
|
||||
testSocksAuthResponseDecoderWithDifferentParams(authStatus);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksAuthResponseTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksAuthResponse(null);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedByteChannel;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksCmdRequestDecoderTest {
|
||||
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SocksCmdRequestDecoderTest.class);
|
||||
|
||||
private void testSocksCmdRequestDecoderWithDifferentParams(SocksMessage.CmdType cmdType, SocksMessage.AddressType addressType, String host, int port) {
|
||||
logger.debug("Testing cmdType: " + cmdType + " addressType: " + addressType + " host: " + host + " port: " + port);
|
||||
SocksCmdRequest msg = new SocksCmdRequest(cmdType, addressType, host, port);
|
||||
SocksCmdRequestDecoder decoder = new SocksCmdRequestDecoder();
|
||||
EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder);
|
||||
SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
if (msg.getAddressType() == SocksMessage.AddressType.UNKNOWN) {
|
||||
assertTrue(embedder.readInbound() instanceof UnknownSocksRequest);
|
||||
} else {
|
||||
msg = (SocksCmdRequest) embedder.readInbound();
|
||||
assertTrue(msg.getCmdType().equals(cmdType));
|
||||
assertTrue(msg.getAddressType().equals(addressType));
|
||||
assertTrue(msg.getHost().equals(host));
|
||||
assertTrue(msg.getPort() == port);
|
||||
}
|
||||
assertNull(embedder.readInbound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCmdRequestDecoderIPv4() {
|
||||
String[] hosts = {"127.0.0.1",};
|
||||
int[] ports = {0, 32769, 65535 };
|
||||
for (SocksMessage.CmdType cmdType : SocksMessage.CmdType.values()) {
|
||||
for (String host : hosts) {
|
||||
for (int port : ports) {
|
||||
testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksMessage.AddressType.IPv4, host, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCmdRequestDecoderIPv6() {
|
||||
String[] hosts = {SocksCommonUtils.ipv6toStr(IPAddressUtil.textToNumericFormatV6("::1"))};
|
||||
int[] ports = {0, 32769, 65535};
|
||||
for (SocksMessage.CmdType cmdType : SocksMessage.CmdType.values()) {
|
||||
for (String host : hosts) {
|
||||
for (int port : ports) {
|
||||
testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksMessage.AddressType.IPv6, host, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCmdRequestDecoderDomain() {
|
||||
String[] hosts = {"google.com" ,
|
||||
"مثال.إختبار",
|
||||
"παράδειγμα.δοκιμή",
|
||||
"مثال.آزمایشی",
|
||||
"пример.испытание",
|
||||
"בײַשפּיל.טעסט",
|
||||
"例子.测试",
|
||||
"例子.測試",
|
||||
"उदाहरण.परीक्षा",
|
||||
"例え.テスト",
|
||||
"실례.테스트",
|
||||
"உதாரணம்.பரிட்சை"};
|
||||
int[] ports = {0, 32769, 65535};
|
||||
for (SocksMessage.CmdType cmdType : SocksMessage.CmdType.values()) {
|
||||
for (String host : hosts) {
|
||||
for (int port : ports) {
|
||||
testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksMessage.AddressType.DOMAIN, host, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCmdRequestDecoderUnknown() {
|
||||
String host = "google.com";
|
||||
int port = 80;
|
||||
for (SocksMessage.CmdType cmdType : SocksMessage.CmdType.values()) {
|
||||
testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksMessage.AddressType.UNKNOWN, host, port);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksCmdRequestTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull(){
|
||||
try {
|
||||
new SocksCmdRequest(null, SocksMessage.AddressType.UNKNOWN, "", 0);
|
||||
} catch (Exception e){
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
|
||||
try {
|
||||
new SocksCmdRequest(SocksMessage.CmdType.UNKNOWN, null, "", 0);
|
||||
} catch (Exception e){
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
|
||||
try {
|
||||
new SocksCmdRequest(SocksMessage.CmdType.UNKNOWN, SocksMessage.AddressType.UNKNOWN, null, 0);
|
||||
} catch (Exception e){
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPv4CorrectAddress(){
|
||||
try {
|
||||
new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.IPv4, "54.54.1111.253", 0);
|
||||
} catch (Exception e){
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPv6CorrectAddress(){
|
||||
try {
|
||||
new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.IPv6, "xxx:xxx:xxx", 0);
|
||||
} catch (Exception e){
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIDNNotExceeds255CharsLimit(){
|
||||
try {
|
||||
new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.DOMAIN,
|
||||
"παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" +
|
||||
"παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" +
|
||||
"παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" +
|
||||
"παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή", 0);
|
||||
} catch (Exception e){
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidPortRange(){
|
||||
try {
|
||||
new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.DOMAIN,
|
||||
"παράδειγμα.δοκιμήπαράδει", -1);
|
||||
} catch (Exception e){
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
|
||||
try {
|
||||
new SocksCmdRequest(SocksMessage.CmdType.BIND, SocksMessage.AddressType.DOMAIN,
|
||||
"παράδειγμα.δοκιμήπαράδει", 65536);
|
||||
} catch (Exception e){
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedByteChannel;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksCmdResponseDecoderTest {
|
||||
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SocksCmdResponseDecoderTest.class);
|
||||
|
||||
private void testSocksCmdResponseDecoderWithDifferentParams(SocksMessage.CmdStatus cmdStatus, SocksMessage.AddressType addressType){
|
||||
logger.debug("Testing cmdStatus: " + cmdStatus + " addressType: " + addressType);
|
||||
SocksResponse msg = new SocksCmdResponse(cmdStatus, addressType);
|
||||
SocksCmdResponseDecoder decoder = new SocksCmdResponseDecoder();
|
||||
EmbeddedByteChannel embedder = new EmbeddedByteChannel(decoder);
|
||||
SocksCommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
if (addressType == SocksMessage.AddressType.UNKNOWN){
|
||||
assertTrue(embedder.readInbound() instanceof UnknownSocksResponse);
|
||||
} else {
|
||||
msg = (SocksCmdResponse) embedder.readInbound();
|
||||
assertTrue(((SocksCmdResponse) msg).getCmdStatus().equals(cmdStatus));
|
||||
}
|
||||
assertNull(embedder.readInbound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSocksCmdResponseDecoder(){
|
||||
for (SocksMessage.CmdStatus cmdStatus: SocksMessage.CmdStatus.values()){
|
||||
for (SocksMessage.AddressType addressType: SocksMessage.AddressType.values()){
|
||||
testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, addressType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksCmdResponseTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksCmdResponse(null, SocksMessage.AddressType.UNKNOWN);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
try {
|
||||
new SocksCmdResponse(SocksMessage.CmdStatus.UNASSIGNED, null);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.embedded.EmbeddedByteChannel;
|
||||
|
||||
class SocksCommonTestUtils {
|
||||
/**
|
||||
* A constructor to stop this class being constructed.
|
||||
*/
|
||||
private SocksCommonTestUtils() {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public static void writeMessageIntoEmbedder(EmbeddedByteChannel embedder, SocksMessage msg) {
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
msg.encodeAsByteBuf(buf);
|
||||
embedder.writeInbound(buf);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksInitRequestTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull(){
|
||||
try {
|
||||
new SocksInitRequest(null);
|
||||
} catch (Exception e){
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.codec.socks;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksInitResponseTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksInitResponse(null);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,41 +14,47 @@
|
||||
~ License for the specific language governing permissions and limitations
|
||||
~ under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-parent</artifactId>
|
||||
<version>4.0.0.Alpha8-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-parent</artifactId>
|
||||
<version>4.0.0.Alpha8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>netty-example</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>netty-example</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Netty/Example</name>
|
||||
<name>Netty/Example</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-transport</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-codec-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-transport</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-codec-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-codec-socks</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.socksproxy;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
public interface CallbackNotifier {
|
||||
void onSuccess(final ChannelHandlerContext outboundCtx);
|
||||
|
||||
void onFailure(final ChannelHandlerContext outboundCtx, final Throwable cause);
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.socksproxy;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundByteHandlerAdapter;
|
||||
|
||||
|
||||
public final class DirectClientHandler extends ChannelInboundByteHandlerAdapter {
|
||||
private static final String name = "DIRECT_CLIENT_HANDLER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
private final CallbackNotifier cb;
|
||||
|
||||
public DirectClientHandler(CallbackNotifier cb) {
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) {
|
||||
ctx.pipeline().remove(this);
|
||||
cb.onSuccess(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) throws Exception {
|
||||
cb.onFailure(ctx, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.socksproxy;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
|
||||
|
||||
public final class DirectClientInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private final CallbackNotifier callbackNotifier;
|
||||
|
||||
public DirectClientInitializer(CallbackNotifier callbackNotifier) {
|
||||
this.callbackNotifier = callbackNotifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
ChannelPipeline channelPipeline = socketChannel.pipeline();
|
||||
channelPipeline.addLast(DirectClientHandler.getName(), new DirectClientHandler(callbackNotifier));
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.socksproxy;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundByteHandlerAdapter;
|
||||
|
||||
|
||||
public final class RelayHandler extends ChannelInboundByteHandlerAdapter {
|
||||
private static final String name = "RELAY_HANDLER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private final Channel relayChannel;
|
||||
|
||||
public RelayHandler(Channel relayChannel) {
|
||||
this.relayChannel = relayChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
ctx.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
|
||||
ByteBuf out = relayChannel.outboundByteBuffer();
|
||||
out.discardReadBytes();
|
||||
out.writeBytes(in);
|
||||
in.clear();
|
||||
if (relayChannel.isActive()) {
|
||||
relayChannel.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
if (relayChannel.isActive()) {
|
||||
SocksServerUtils.closeOnFlush(relayChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.socksproxy;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.socket.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
|
||||
public final class SocksServer {
|
||||
private final int localPort;
|
||||
|
||||
public SocksServer(int localPort) {
|
||||
this.localPort = localPort;
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
System.err.println(
|
||||
"Listening on*:" + localPort + "...");
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
try {
|
||||
b.group(new NioEventLoopGroup(), new NioEventLoopGroup())
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.localAddress(localPort)
|
||||
.childHandler(new SocksServerInitializer());
|
||||
b.bind().sync().channel().closeFuture().sync();
|
||||
} finally {
|
||||
b.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new SocksServer(1080).run();
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.socksproxy;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.codec.socks.SocksCmdRequest;
|
||||
import io.netty.codec.socks.SocksCmdResponse;
|
||||
import io.netty.codec.socks.SocksMessage;
|
||||
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public final class SocksServerConnectHandler extends ChannelInboundMessageHandlerAdapter<SocksCmdRequest> {
|
||||
private static final String name = "SOCKS_SERVER_CONNECT_HANDLER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private final Bootstrap b;
|
||||
|
||||
public SocksServerConnectHandler() {
|
||||
super(SocksCmdRequest.class);
|
||||
b = new Bootstrap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(final ChannelHandlerContext ctx, final SocksCmdRequest request) throws Exception {
|
||||
CallbackNotifier cb = new CallbackNotifier() {
|
||||
public void onSuccess(final ChannelHandlerContext outboundCtx) {
|
||||
ctx.channel().write(new SocksCmdResponse(SocksMessage.CmdStatus.SUCCESS, request.getAddressType()))
|
||||
.addListener(new ChannelFutureListener() {
|
||||
public void operationComplete(ChannelFuture channelFuture) throws Exception {
|
||||
ctx.pipeline().remove(SocksServerConnectHandler.getName());
|
||||
outboundCtx.channel().pipeline().addLast(new RelayHandler(ctx.channel()));
|
||||
ctx.channel().pipeline().addLast(new RelayHandler(outboundCtx.channel()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onFailure(ChannelHandlerContext outboundCtx, Throwable cause) {
|
||||
ctx.channel().write(new SocksCmdResponse(SocksMessage.CmdStatus.FAILURE, request.getAddressType()));
|
||||
SocksServerUtils.closeOnFlush(ctx.channel());
|
||||
}
|
||||
};
|
||||
|
||||
final Channel inboundChannel = ctx.channel();
|
||||
b.group(inboundChannel.eventLoop())
|
||||
.channel(NioSocketChannel.class)
|
||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
|
||||
.option(ChannelOption.SO_KEEPALIVE, true)
|
||||
.handler(new DirectClientInitializer(cb))
|
||||
.remoteAddress(request.getHost(), request.getPort());
|
||||
ChannelFuture f = b.connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
SocksServerUtils.closeOnFlush(ctx.channel());
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.socksproxy;
|
||||
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
|
||||
import io.netty.codec.socks.SocksCmdRequestDecoder;
|
||||
import io.netty.codec.socks.SocksInitResponse;
|
||||
import io.netty.codec.socks.SocksMessage;
|
||||
import io.netty.codec.socks.SocksRequest;
|
||||
import io.netty.codec.socks.SocksAuthResponse;
|
||||
import io.netty.codec.socks.SocksCmdRequest;
|
||||
import io.netty.codec.socks.SocksCmdResponse;
|
||||
|
||||
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public final class SocksServerHandler extends ChannelInboundMessageHandlerAdapter<SocksRequest> {
|
||||
private static final String name = "SOCKS_SERVER_HANDLER";
|
||||
|
||||
public static String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public SocksServerHandler() {
|
||||
super(SocksRequest.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, SocksRequest socksRequest) throws Exception {
|
||||
switch (socksRequest.getSocksRequestType()) {
|
||||
case INIT: {
|
||||
// auth support example
|
||||
// ctx.pipeline().addFirst("socksAuthRequestDecoder",new SocksAuthRequestDecoder());
|
||||
// ctx.write(new SocksInitResponse(SocksMessage.AuthScheme.AUTH_PASSWORD));
|
||||
ctx.pipeline().addFirst(SocksCmdRequestDecoder.getName(), new SocksCmdRequestDecoder());
|
||||
ctx.write(new SocksInitResponse(SocksMessage.AuthScheme.NO_AUTH));
|
||||
break;
|
||||
}
|
||||
case AUTH:
|
||||
ctx.pipeline().addFirst(SocksCmdRequestDecoder.getName(), new SocksCmdRequestDecoder());
|
||||
ctx.write(new SocksAuthResponse(SocksMessage.AuthStatus.SUCCESS));
|
||||
break;
|
||||
case CMD:
|
||||
SocksCmdRequest req = (SocksCmdRequest) socksRequest;
|
||||
if (req.getCmdType() == SocksMessage.CmdType.CONNECT) {
|
||||
ctx.pipeline().addLast(SocksServerConnectHandler.getName(), new SocksServerConnectHandler());
|
||||
ctx.pipeline().remove(this);
|
||||
ctx.nextInboundMessageBuffer().add(socksRequest);
|
||||
ctx.fireInboundBufferUpdated();
|
||||
} else {
|
||||
ctx.close();
|
||||
}
|
||||
break;
|
||||
case UNKNOWN:
|
||||
ctx.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(io.netty.channel.ChannelHandlerContext ctx, Throwable throwable) throws Exception {
|
||||
throwable.printStackTrace();
|
||||
SocksServerUtils.closeOnFlush(ctx.channel());
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.socksproxy;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.codec.socks.SocksInitRequestDecoder;
|
||||
import io.netty.codec.socks.SocksMessageEncoder;
|
||||
|
||||
public final class SocksServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||
private SocksMessageEncoder socksMessageEncoder = new SocksMessageEncoder();
|
||||
private SocksServerHandler socksServerHandler = new SocksServerHandler();
|
||||
|
||||
public SocksServerInitializer() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
ChannelPipeline channelPipeline = socketChannel.pipeline();
|
||||
channelPipeline.addLast(SocksInitRequestDecoder.getName(), new SocksInitRequestDecoder());
|
||||
channelPipeline.addLast(SocksMessageEncoder.getName(), socksMessageEncoder);
|
||||
channelPipeline.addLast(SocksServerHandler.getName(), socksServerHandler);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.example.socksproxy;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
|
||||
public final class SocksServerUtils {
|
||||
|
||||
private SocksServerUtils() {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the specified channel after all queued write requests are flushed.
|
||||
*/
|
||||
public static void closeOnFlush(Channel ch) {
|
||||
if (ch.isActive()) {
|
||||
ch.flush().addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
}
|
2
pom.xml
2
pom.xml
@ -77,6 +77,7 @@
|
||||
<module>buffer</module>
|
||||
<module>codec</module>
|
||||
<module>codec-http</module>
|
||||
<module>codec-socks</module>
|
||||
<module>transport</module>
|
||||
<module>handler</module>
|
||||
<module>metrics-yammer</module>
|
||||
@ -278,6 +279,7 @@
|
||||
<ignores>
|
||||
<ignore>sun.misc.Unsafe</ignore>
|
||||
<ignore>sun.misc.Cleaner</ignore>
|
||||
<ignore>sun.net.util.IPAddressUtil</ignore>
|
||||
|
||||
<ignore>java.util.zip.Deflater</ignore>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user