basic support for socks5 codec

This commit is contained in:
alexey 2012-11-07 22:54:00 +04:00 committed by Norman Maurer
parent ef26ffe9d8
commit 5d2b41c094
44 changed files with 2722 additions and 31 deletions

43
codec-socks/pom.xml Normal file
View 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>

View File

@ -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));
}
}

View File

@ -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
}
}

View File

@ -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());
}
}

View File

@ -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
}
}

View File

@ -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;
}
}
}
}

View File

@ -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
}
}

View File

@ -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;
}
}
}
}

View File

@ -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
}
}

View File

@ -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);
}
}
}
}

View File

@ -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());
}
}
}

View File

@ -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
}
}

View File

@ -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());
}
}

View File

@ -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
}
}

View 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);
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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);
}

View File

@ -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 {
}
}

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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>