Add socksx package which supports SOCKS 4/4a/5
Motivation: SOCKS 4 and 5 are very different protocols although they share the same name. It is not possible to incorporate the two protocol versions into a single package. Modifications: - Add a new package called 'socksx' to supercede 'socks' package. - Add SOCKS 4/4a support to the 'socksx' package Result: codec-socks now supports all SOCKS versions
This commit is contained in:
parent
951ff902bd
commit
a242224646
66
codec-socks/src/main/java/io/netty/handler/codec/socksx/SocksMessage.java
Executable file
66
codec-socks/src/main/java/io/netty/handler/codec/socksx/SocksMessage.java
Executable 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.handler.codec.socksx;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An abstract class that defines a SocksMessage, providing common properties for
|
||||
* {@link SocksV5Request} and {@link SocksV5Response}.
|
||||
*
|
||||
* @see SocksV5Request
|
||||
* @see SocksV5Response
|
||||
*/
|
||||
|
||||
public abstract class SocksMessage {
|
||||
private final SocksMessageType type;
|
||||
private final SocksProtocolVersion protocolVersion;
|
||||
|
||||
protected SocksMessage(SocksProtocolVersion protocolVersion, SocksMessageType type) {
|
||||
if (protocolVersion == null) {
|
||||
throw new NullPointerException("protocolVersion");
|
||||
}
|
||||
if (type == null) {
|
||||
throw new NullPointerException("type");
|
||||
}
|
||||
this.protocolVersion = protocolVersion;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocksMessageType} of this {@link SocksMessage}
|
||||
*
|
||||
* @return The {@link SocksMessageType} of this {@link SocksMessage}
|
||||
*/
|
||||
public SocksMessageType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocksProtocolVersion} of this {@link SocksMessage}
|
||||
*
|
||||
* @return The {@link SocksProtocolVersion} of this {@link SocksMessage}
|
||||
*/
|
||||
public SocksProtocolVersion protocolVersion() {
|
||||
return protocolVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Do not use; this method was intended for an internal use only.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract void encodeAsByteBuf(ByteBuf byteBuf);
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx;
|
||||
|
||||
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 SocksV4CmdRequest},
|
||||
* {@link SocksV4CmdRequest},
|
||||
* {@link SocksV5InitRequest},
|
||||
* {@link SocksV5InitResponse},
|
||||
* {@link SocksV5AuthRequest},
|
||||
* {@link SocksV5AuthResponse},
|
||||
* {@link SocksV5CmdRequest} and
|
||||
* {@link SocksV5CmdResponse}
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class SocksMessageEncoder extends MessageToByteEncoder<SocksMessage> {
|
||||
private static final String name = "SOCKS_MESSAGE_ENCODER";
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void encode(ChannelHandlerContext ctx, SocksMessage msg, ByteBuf out) throws Exception {
|
||||
msg.encodeAsByteBuf(out);
|
||||
}
|
||||
|
||||
private static class SocksMessageEncoderHolder {
|
||||
public static final SocksMessageEncoder HOLDER_INSTANCE = new SocksMessageEncoder();
|
||||
}
|
||||
|
||||
public static SocksMessageEncoder getInstance() {
|
||||
return SocksMessageEncoderHolder.HOLDER_INSTANCE;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx;
|
||||
|
||||
public enum SocksMessageType {
|
||||
REQUEST,
|
||||
RESPONSE,
|
||||
UNKNOWN
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx;
|
||||
|
||||
public enum SocksProtocolVersion {
|
||||
SOCKS4a((byte) 0x04),
|
||||
SOCKS5((byte) 0x05),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
SocksProtocolVersion(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #valueOf(byte)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static SocksProtocolVersion fromByte(byte b) {
|
||||
return valueOf(b);
|
||||
}
|
||||
|
||||
public static SocksProtocolVersion valueOf(byte b) {
|
||||
for (SocksProtocolVersion code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return b;
|
||||
}
|
||||
}
|
@ -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.handler.codec.socksx;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An abstract class that defines a SocksRequest, providing common properties for
|
||||
* {@link SocksV5InitRequest},
|
||||
* {@link SocksV5AuthRequest},
|
||||
* {@link SocksV5CmdRequest}
|
||||
* and {@link UnknownSocksV5Request}.
|
||||
*
|
||||
* @see io.netty.handler.codec.socks.SocksInitRequest
|
||||
* @see io.netty.handler.codec.socks.SocksAuthRequest
|
||||
* @see io.netty.handler.codec.socks.SocksCmdRequest
|
||||
* @see io.netty.handler.codec.socks.UnknownSocksRequest
|
||||
*/
|
||||
public abstract class SocksRequest extends SocksMessage {
|
||||
|
||||
protected SocksRequest(SocksProtocolVersion protocolVersion) {
|
||||
super(protocolVersion, SocksMessageType.REQUEST);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx;
|
||||
|
||||
public abstract class SocksResponse extends SocksMessage {
|
||||
protected SocksResponse(SocksProtocolVersion protocolVersion) {
|
||||
super(protocolVersion, SocksMessageType.RESPONSE);
|
||||
}
|
||||
}
|
20
codec-socks/src/main/java/io/netty/handler/codec/socksx/package-info.java
Executable file
20
codec-socks/src/main/java/io/netty/handler/codec/socksx/package-info.java
Executable file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2014 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.handler.codec.socksx;
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.NetUtil;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
|
||||
import java.net.IDN;
|
||||
|
||||
/**
|
||||
* An socksv4a cmd request.
|
||||
*
|
||||
* @see SocksV4Response
|
||||
* @see SocksV4CmdRequestDecoder
|
||||
*/
|
||||
|
||||
public final class SocksV4CmdRequest extends SocksV4Request {
|
||||
private final String userId;
|
||||
private final SocksV4CmdType cmdType;
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
private static final byte[] IPv4_DOMAIN_MARKER = {0x00, 0x00, 0x00, 0x01};
|
||||
|
||||
public SocksV4CmdRequest(String userId, SocksV4CmdType cmdType, String host, int port) {
|
||||
if (userId == null) {
|
||||
throw new NullPointerException("username");
|
||||
}
|
||||
if (cmdType == null) {
|
||||
throw new NullPointerException("cmdType");
|
||||
}
|
||||
if (host == null) {
|
||||
throw new NullPointerException("host");
|
||||
}
|
||||
if (port <= 0 || port >= 65536) {
|
||||
throw new IllegalArgumentException(port + " is not in bounds 0 < x < 65536");
|
||||
}
|
||||
this.userId = userId;
|
||||
this.cmdType = cmdType;
|
||||
this.host = IDN.toASCII(host);
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public SocksV4CmdRequest(SocksV4CmdType cmdType, String host, int port) {
|
||||
this("", cmdType, host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocksV4CmdType} of this {@link SocksV4Request}
|
||||
*
|
||||
* @return The {@link SocksV4CmdType} of this {@link SocksV4Request}
|
||||
*/
|
||||
public SocksV4CmdType cmdType() {
|
||||
return cmdType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns host that is used as a parameter in {@link SocksV4CmdType}
|
||||
*
|
||||
* @return host that is used as a parameter in {@link SocksV4CmdType}
|
||||
*/
|
||||
public String host() {
|
||||
return IDN.toUnicode(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns userId that is used as a parameter in {@link SocksV4CmdType}
|
||||
*
|
||||
* @return userId that is used as a parameter in {@link SocksV4CmdType}
|
||||
*/
|
||||
public String userId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns port that is used as a parameter in {@link SocksV4CmdType}
|
||||
*
|
||||
* @return port that is used as a parameter in {@link SocksV4CmdType}
|
||||
*/
|
||||
public int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(protocolVersion().byteValue());
|
||||
byteBuf.writeByte(cmdType.byteValue());
|
||||
byteBuf.writeShort(port);
|
||||
if (NetUtil.isValidIpV4Address(host)) {
|
||||
byteBuf.writeBytes(NetUtil.createByteArrayFromIpAddressString(host));
|
||||
byteBuf.writeBytes(userId.getBytes());
|
||||
byteBuf.writeZero(1);
|
||||
} else {
|
||||
byteBuf.writeBytes(IPv4_DOMAIN_MARKER);
|
||||
byteBuf.writeBytes(userId.getBytes());
|
||||
byteBuf.writeZero(1);
|
||||
byteBuf.writeBytes(host.getBytes(CharsetUtil.US_ASCII));
|
||||
byteBuf.writeZero(1);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.v4.SocksV4CmdRequestDecoder.State;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksV4CmdRequest}.
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksV4CmdRequestDecoder extends ReplayingDecoder<State> {
|
||||
private static final String name = "SOCKS_CMD_REQUEST_DECODER";
|
||||
|
||||
private SocksProtocolVersion version;
|
||||
private SocksV4CmdType cmdType;
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private byte reserved;
|
||||
private String host;
|
||||
private int port;
|
||||
private String userId;
|
||||
private SocksV4Request msg = UnknownSocksV4Request.getInstance();
|
||||
|
||||
public SocksV4CmdRequestDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksProtocolVersion.valueOf(byteBuf.readByte());
|
||||
if (version != SocksProtocolVersion.SOCKS4a) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_CMD_HEADER);
|
||||
}
|
||||
case READ_CMD_HEADER: {
|
||||
cmdType = SocksV4CmdType.valueOf(byteBuf.readByte());
|
||||
port = byteBuf.readUnsignedShort();
|
||||
host = SocksV4CommonUtils.intToIp(byteBuf.readInt());
|
||||
checkpoint(State.READ_CMD_USERID);
|
||||
}
|
||||
case READ_CMD_USERID: {
|
||||
userId = readNullTerminatedString(byteBuf);
|
||||
checkpoint(State.READ_CMD_DOMAIN);
|
||||
}
|
||||
case READ_CMD_DOMAIN: {
|
||||
// Check for Socks4a protocol marker 0,0,0,x
|
||||
if (!host.equals("0.0.0.0") && host.startsWith("0.0.0.")) {
|
||||
host = readNullTerminatedString(byteBuf);
|
||||
}
|
||||
msg = new SocksV4CmdRequest(userId, cmdType, host, port);
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
out.add(msg);
|
||||
}
|
||||
private static String readNullTerminatedString(ByteBuf byteBuf) throws Exception {
|
||||
byte NULL_BYTE = (byte) 0x00;
|
||||
// Could be used for DoS
|
||||
String string = byteBuf.readBytes(byteBuf.bytesBefore(NULL_BYTE)).toString(CharsetUtil.US_ASCII);
|
||||
// Read NULL-byte
|
||||
byteBuf.readByte();
|
||||
return string;
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_CMD_HEADER,
|
||||
READ_CMD_USERID,
|
||||
READ_CMD_DOMAIN
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.NetUtil;
|
||||
|
||||
import java.net.IDN;
|
||||
|
||||
/**
|
||||
* A socks cmd response.
|
||||
*
|
||||
* @see SocksV4CmdRequest
|
||||
* @see SocksV4CmdResponseDecoder
|
||||
*/
|
||||
public final class SocksV4CmdResponse extends SocksV4Response {
|
||||
private final SocksV4CmdStatus cmdStatus;
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
// 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 };
|
||||
|
||||
public SocksV4CmdResponse(SocksV4CmdStatus cmdStatus) {
|
||||
this(cmdStatus, null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new response and includes provided host and port as part of it.
|
||||
*
|
||||
* @param cmdStatus status of the response
|
||||
* @param host host (BND.ADDR field) is address that server used when connecting to the target host.
|
||||
* When null a value of 4/8 0x00 octets will be used for IPv4/IPv6 and a single 0x00 byte will be
|
||||
* used for domain addressType. Value is converted to ASCII using {@link java.net.IDN#toASCII(String)}.
|
||||
* @param port port (BND.PORT field) that the server assigned to connect to the target host
|
||||
* @throws NullPointerException in case cmdStatus or addressType are missing
|
||||
* @throws IllegalArgumentException in case host or port cannot be validated
|
||||
* @see java.net.IDN#toASCII(String)
|
||||
*/
|
||||
public SocksV4CmdResponse(SocksV4CmdStatus cmdStatus, String host, int port) {
|
||||
if (cmdStatus == null) {
|
||||
throw new NullPointerException("cmdStatus");
|
||||
}
|
||||
if (host != null) {
|
||||
if (!NetUtil.isValidIpV4Address(host)) {
|
||||
throw new IllegalArgumentException(host + " is not a valid IPv4 address");
|
||||
}
|
||||
}
|
||||
if (port < 0 || port > 65535) {
|
||||
throw new IllegalArgumentException(port + " is not in bounds 0 <= x <= 65535");
|
||||
}
|
||||
this.cmdStatus = cmdStatus;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocksV4CmdStatus} of this {@link SocksV4Response}
|
||||
*
|
||||
* @return The {@link SocksV4CmdStatus} of this {@link SocksV4Response}
|
||||
*/
|
||||
public SocksV4CmdStatus cmdStatus() {
|
||||
return cmdStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns host that is used as a parameter in {@link io.netty.handler.codec.socks.v4.SocksV4CmdType}.
|
||||
* Host (BND.ADDR field in response) is address that server used when connecting to the target host.
|
||||
* This is typically different from address which client uses to connect to the SOCKS server.
|
||||
*
|
||||
* @return host that is used as a parameter in {@link io.netty.handler.codec.socks.v4.SocksV4CmdType}
|
||||
* or null when there was no host specified during response construction
|
||||
*/
|
||||
public String host() {
|
||||
if (host != null) {
|
||||
return IDN.toUnicode(host);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns port that is used as a parameter in {@link io.netty.handler.codec.socks.v4.SocksV4CmdType}.
|
||||
* Port (BND.PORT field in response) is port that the server assigned to connect to the target host.
|
||||
*
|
||||
* @return port that is used as a parameter in {@link io.netty.handler.codec.socks.v4.SocksV4CmdType}
|
||||
*/
|
||||
public int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeZero(1);
|
||||
byteBuf.writeByte(cmdStatus.byteValue());
|
||||
byteBuf.writeShort(port);
|
||||
byte[] hostContent = host == null ?
|
||||
IPv4_HOSTNAME_ZEROED : NetUtil.createByteArrayFromIpAddressString(host);
|
||||
byteBuf.writeBytes(hostContent);
|
||||
}
|
||||
}
|
@ -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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.handler.codec.socks.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.v4.SocksV4CmdResponseDecoder.State;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksV4CmdResponse}.
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksV4CmdResponseDecoder extends ReplayingDecoder<State> {
|
||||
private static final String name = "SOCKS_CMD_RESPONSE_DECODER";
|
||||
|
||||
private SocksProtocolVersion version;
|
||||
private SocksV4CmdStatus cmdStatus;
|
||||
|
||||
private String host;
|
||||
private int port;
|
||||
private SocksV4Response msg = UnknownSocksV4Response.getInstance();
|
||||
|
||||
public SocksV4CmdResponseDecoder() {
|
||||
super(State.CHECK_NULL_BYTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_NULL_BYTE: {
|
||||
if (byteBuf.readByte() != (byte) 0x00) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_CMD_HEADER);
|
||||
}
|
||||
case READ_CMD_HEADER: {
|
||||
cmdStatus = SocksV4CmdStatus.valueOf(byteBuf.readByte());
|
||||
checkpoint(State.READ_CMD_ADDRESS);
|
||||
}
|
||||
case READ_CMD_ADDRESS: {
|
||||
port = byteBuf.readUnsignedShort();
|
||||
host = SocksV4CommonUtils.intToIp(byteBuf.readInt());
|
||||
msg = new SocksV4CmdResponse(cmdStatus, host, port);
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
out.add(msg);
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_NULL_BYTE,
|
||||
READ_CMD_HEADER,
|
||||
READ_CMD_ADDRESS
|
||||
}
|
||||
}
|
@ -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.handler.codec.socksx.v4;
|
||||
|
||||
public enum SocksV4CmdStatus {
|
||||
SUCCESS((byte) 0x5a),
|
||||
REJECTED_OR_FAILED((byte) 0x5b),
|
||||
IDENTD_UNREACHABLE((byte) 0x5c),
|
||||
IDENTD_AUTH_FAILURE((byte) 0x5d),
|
||||
UNASSIGNED((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
SocksV4CmdStatus(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static SocksV4CmdStatus valueOf(byte b) {
|
||||
for (SocksV4CmdStatus code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNASSIGNED;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return b;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
public enum SocksV4CmdType {
|
||||
CONNECT((byte) 0x01),
|
||||
BIND((byte) 0x02),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
SocksV4CmdType(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static SocksV4CmdType valueOf(byte b) {
|
||||
for (SocksV4CmdType code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return b;
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
public final class SocksV4CommonUtils {
|
||||
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 SocksV4CommonUtils() {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
public static String intToIp(int i) {
|
||||
return String.valueOf(i >> FIRST_ADDRESS_OCTET_SHIFT & XOR_DEFAULT_VALUE) + '.' +
|
||||
(i >> SECOND_ADDRESS_OCTET_SHIFT & XOR_DEFAULT_VALUE) + '.' +
|
||||
(i >> THIRD_ADDRESS_OCTET_SHIFT & XOR_DEFAULT_VALUE) + '.' +
|
||||
(i & XOR_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts numeric IPv6 to standard (non-compressed) format.
|
||||
*/
|
||||
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) {
|
||||
int i;
|
||||
toHextet --;
|
||||
for (i = fromHextet; i < toHextet; i++) {
|
||||
appendHextet(sb, src, i);
|
||||
sb.append(ipv6hextetSeparator);
|
||||
}
|
||||
|
||||
appendHextet(sb, src, i);
|
||||
}
|
||||
|
||||
private static void appendHextet(StringBuilder sb, byte[] src, int i) {
|
||||
StringUtil.toHexString(sb, src, i << 1, 2);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.handler.codec.socksx.SocksMessage;
|
||||
import io.netty.handler.codec.socksx.SocksMessageType;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.SocksRequest;
|
||||
|
||||
/**
|
||||
* An abstract class that defines a SocksRequest, providing common properties for
|
||||
* {@link SocksV4CmdRequest}.
|
||||
*
|
||||
* @see SocksV4CmdRequest
|
||||
* @see UnknownSocksV4Request
|
||||
*/
|
||||
public abstract class SocksV4Request extends SocksRequest {
|
||||
protected SocksV4Request() {
|
||||
super(SocksProtocolVersion.SOCKS4a);
|
||||
}
|
||||
}
|
@ -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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.handler.codec.socksx.SocksMessage;
|
||||
import io.netty.handler.codec.socksx.SocksMessageType;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.SocksResponse;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5ResponseType;
|
||||
|
||||
/**
|
||||
* An abstract class that defines a SocksResponse, providing common properties for
|
||||
* {@link SocksV4CmdResponse}.
|
||||
*
|
||||
* @see SocksV4CmdResponse
|
||||
* @see UnknownSocksV4Response
|
||||
*/
|
||||
public abstract class SocksV4Response extends SocksResponse {
|
||||
|
||||
protected SocksV4Response() {
|
||||
super(SocksProtocolVersion.SOCKS4a);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An unknown socks request.
|
||||
*
|
||||
* @see SocksV4CmdRequestDecoder
|
||||
*/
|
||||
public final class UnknownSocksV4Request extends SocksV4Request {
|
||||
|
||||
public UnknownSocksV4Request() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
private static class UnknownSocksV4RequestHolder {
|
||||
public static final UnknownSocksV4Request HOLDER_INSTANCE = new UnknownSocksV4Request();
|
||||
}
|
||||
|
||||
public static UnknownSocksV4Request getInstance() {
|
||||
return UnknownSocksV4RequestHolder.HOLDER_INSTANCE;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An unknown socks response.
|
||||
*
|
||||
* @see SocksV4CmdResponseDecoder
|
||||
*/
|
||||
public final class UnknownSocksV4Response extends SocksV4Response {
|
||||
|
||||
public UnknownSocksV4Response() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
private static class UnknownSocksV4ResponseHolder {
|
||||
public static final UnknownSocksV4Response HOLDER_INSTANCE = new UnknownSocksV4Response();
|
||||
}
|
||||
|
||||
public static UnknownSocksV4Response getInstance() {
|
||||
return UnknownSocksV4ResponseHolder.HOLDER_INSTANCE;
|
||||
}
|
||||
}
|
20
codec-socks/src/main/java/io/netty/handler/codec/socksx/v4/package-info.java
Executable file
20
codec-socks/src/main/java/io/netty/handler/codec/socksx/v4/package-info.java
Executable file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2014 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.handler.codec.socksx.v4;
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx.v5;
|
||||
|
||||
public enum SocksV5AddressType {
|
||||
IPv4((byte) 0x01),
|
||||
DOMAIN((byte) 0x03),
|
||||
IPv6((byte) 0x04),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
SocksV5AddressType(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static SocksV5AddressType valueOf(byte b) {
|
||||
for (SocksV5AddressType code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
/**
|
||||
* An socks auth request.
|
||||
*
|
||||
* @see SocksV5AuthResponse
|
||||
* @see SocksV5AuthRequestDecoder
|
||||
*/
|
||||
public final class SocksV5AuthRequest extends SocksV5Request {
|
||||
private static final CharsetEncoder asciiEncoder = CharsetUtil.getEncoder(CharsetUtil.US_ASCII);
|
||||
private static final SocksV5SubnegotiationVersion SUBNEGOTIATION_VERSION =
|
||||
SocksV5SubnegotiationVersion.AUTH_PASSWORD;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public SocksV5AuthRequest(String username, String password) {
|
||||
super(SocksV5RequestType.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 username() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns password that needs to be validated
|
||||
*
|
||||
* @return password that needs to be validated
|
||||
*/
|
||||
public String password() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(SUBNEGOTIATION_VERSION.byteValue());
|
||||
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,71 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5AuthRequestDecoder.State;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksV5AuthRequest}.
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksV5AuthRequestDecoder extends ReplayingDecoder<State> {
|
||||
private SocksV5SubnegotiationVersion version;
|
||||
private int fieldLength;
|
||||
private String username;
|
||||
private String password;
|
||||
private SocksV5Request msg = UnknownSocksV5Request.getInstance();
|
||||
|
||||
public SocksV5AuthRequestDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksV5SubnegotiationVersion.valueOf(byteBuf.readByte());
|
||||
if (version != SocksV5SubnegotiationVersion.AUTH_PASSWORD) {
|
||||
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 SocksV5AuthRequest(username, password);
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
out.add(msg);
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_USERNAME,
|
||||
READ_PASSWORD
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An socks auth response.
|
||||
*
|
||||
* @see SocksV5AuthRequest
|
||||
* @see SocksV5AuthResponseDecoder
|
||||
*/
|
||||
public final class SocksV5AuthResponse extends SocksV5Response {
|
||||
private static final SocksV5SubnegotiationVersion SUBNEGOTIATION_VERSION =
|
||||
SocksV5SubnegotiationVersion.AUTH_PASSWORD;
|
||||
private final SocksV5AuthStatus authStatus;
|
||||
|
||||
public SocksV5AuthResponse(SocksV5AuthStatus authStatus) {
|
||||
super(SocksV5ResponseType.AUTH);
|
||||
if (authStatus == null) {
|
||||
throw new NullPointerException("authStatus");
|
||||
}
|
||||
this.authStatus = authStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocksV5AuthStatus} of this {@link SocksV5AuthResponse}
|
||||
*
|
||||
* @return The {@link SocksV5AuthStatus} of this {@link SocksV5AuthResponse}
|
||||
*/
|
||||
public SocksV5AuthStatus authStatus() {
|
||||
return authStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(SUBNEGOTIATION_VERSION.byteValue());
|
||||
byteBuf.writeByte(authStatus.byteValue());
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5AuthResponseDecoder.State;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksV5AuthResponse}.
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksV5AuthResponseDecoder extends ReplayingDecoder<State> {
|
||||
private SocksV5SubnegotiationVersion version;
|
||||
private SocksV5AuthStatus authStatus;
|
||||
private SocksV5Response msg = UnknownSocksV5Response.getInstance();
|
||||
|
||||
public SocksV5AuthResponseDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> out)
|
||||
throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksV5SubnegotiationVersion.valueOf(byteBuf.readByte());
|
||||
if (version != SocksV5SubnegotiationVersion.AUTH_PASSWORD) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_AUTH_RESPONSE);
|
||||
}
|
||||
case READ_AUTH_RESPONSE: {
|
||||
authStatus = SocksV5AuthStatus.valueOf(byteBuf.readByte());
|
||||
msg = new SocksV5AuthResponse(authStatus);
|
||||
}
|
||||
}
|
||||
channelHandlerContext.pipeline().remove(this);
|
||||
out.add(msg);
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_AUTH_RESPONSE
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx.v5;
|
||||
|
||||
public enum SocksV5AuthScheme {
|
||||
NO_AUTH((byte) 0x00),
|
||||
AUTH_GSSAPI((byte) 0x01),
|
||||
AUTH_PASSWORD((byte) 0x02),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
SocksV5AuthScheme(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static SocksV5AuthScheme valueOf(byte b) {
|
||||
for (SocksV5AuthScheme code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx.v5;
|
||||
|
||||
public enum SocksV5AuthStatus {
|
||||
SUCCESS((byte) 0x00),
|
||||
FAILURE((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
SocksV5AuthStatus(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static SocksV5AuthStatus valueOf(byte b) {
|
||||
for (SocksV5AuthStatus code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.NetUtil;
|
||||
|
||||
import java.net.IDN;
|
||||
|
||||
/**
|
||||
* An socks cmd request.
|
||||
*
|
||||
* @see SocksV5CmdResponse
|
||||
* @see SocksV5CmdRequestDecoder
|
||||
*/
|
||||
public final class SocksV5CmdRequest extends SocksV5Request {
|
||||
private final SocksV5CmdType cmdType;
|
||||
private final SocksV5AddressType addressType;
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
public SocksV5CmdRequest(SocksV5CmdType cmdType, SocksV5AddressType addressType, String host, int port) {
|
||||
super(SocksV5RequestType.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 (!NetUtil.isValidIpV4Address(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 (!NetUtil.isValidIpV6Address(host)) {
|
||||
throw new IllegalArgumentException(host + " is not a valid IPv6 address");
|
||||
}
|
||||
break;
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
if (port <= 0 || port >= 65536) {
|
||||
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 SocksV5CmdType} of this {@link SocksV5CmdRequest}
|
||||
*
|
||||
* @return The {@link SocksV5CmdType} of this {@link SocksV5CmdRequest}
|
||||
*/
|
||||
public SocksV5CmdType cmdType() {
|
||||
return cmdType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocksV5AddressType} of this {@link SocksV5CmdRequest}
|
||||
*
|
||||
* @return The {@link SocksV5AddressType} of this {@link SocksV5CmdRequest}
|
||||
*/
|
||||
public SocksV5AddressType addressType() {
|
||||
return addressType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns host that is used as a parameter in {@link SocksV5CmdType}
|
||||
*
|
||||
* @return host that is used as a parameter in {@link SocksV5CmdType}
|
||||
*/
|
||||
public String host() {
|
||||
return IDN.toUnicode(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns port that is used as a parameter in {@link SocksV5CmdType}
|
||||
*
|
||||
* @return port that is used as a parameter in {@link SocksV5CmdType}
|
||||
*/
|
||||
public int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(protocolVersion().byteValue());
|
||||
byteBuf.writeByte(cmdType.byteValue());
|
||||
byteBuf.writeByte(0x00);
|
||||
byteBuf.writeByte(addressType.byteValue());
|
||||
switch (addressType) {
|
||||
case IPv4: {
|
||||
byteBuf.writeBytes(NetUtil.createByteArrayFromIpAddressString(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(NetUtil.createByteArrayFromIpAddressString(host));
|
||||
byteBuf.writeShort(port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdRequestDecoder.State;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksV5CmdRequest}.
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksV5CmdRequestDecoder extends ReplayingDecoder<State> {
|
||||
private SocksProtocolVersion version;
|
||||
private int fieldLength;
|
||||
private SocksV5CmdType cmdType;
|
||||
private SocksV5AddressType addressType;
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private byte reserved;
|
||||
private String host;
|
||||
private int port;
|
||||
private SocksV5Request msg = UnknownSocksV5Request.getInstance();
|
||||
|
||||
public SocksV5CmdRequestDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksProtocolVersion.valueOf(byteBuf.readByte());
|
||||
if (version != SocksProtocolVersion.SOCKS5) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_CMD_HEADER);
|
||||
}
|
||||
case READ_CMD_HEADER: {
|
||||
cmdType = SocksV5CmdType.valueOf(byteBuf.readByte());
|
||||
reserved = byteBuf.readByte();
|
||||
addressType = SocksV5AddressType.valueOf(byteBuf.readByte());
|
||||
checkpoint(State.READ_CMD_ADDRESS);
|
||||
}
|
||||
case READ_CMD_ADDRESS: {
|
||||
switch (addressType) {
|
||||
case IPv4: {
|
||||
host = SocksV5CommonUtils.intToIp(byteBuf.readInt());
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksV5CmdRequest(cmdType, addressType, host, port);
|
||||
break;
|
||||
}
|
||||
case DOMAIN: {
|
||||
fieldLength = byteBuf.readByte();
|
||||
host = byteBuf.readBytes(fieldLength).toString(CharsetUtil.US_ASCII);
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksV5CmdRequest(cmdType, addressType, host, port);
|
||||
break;
|
||||
}
|
||||
case IPv6: {
|
||||
host = SocksV5CommonUtils.ipv6toStr(byteBuf.readBytes(16).array());
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksV5CmdRequest(cmdType, addressType, host, port);
|
||||
break;
|
||||
}
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
out.add(msg);
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_CMD_HEADER,
|
||||
READ_CMD_ADDRESS
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.NetUtil;
|
||||
|
||||
import java.net.IDN;
|
||||
|
||||
/**
|
||||
* A socks cmd response.
|
||||
*
|
||||
* @see SocksV5CmdRequest
|
||||
* @see SocksV5CmdResponseDecoder
|
||||
*/
|
||||
public final class SocksV5CmdResponse extends SocksV5Response {
|
||||
private final SocksV5CmdStatus cmdStatus;
|
||||
|
||||
private final SocksV5AddressType addressType;
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
// All arrays are initialized on construction time to 0/false/null remove array Initialization
|
||||
private static final byte[] DOMAIN_ZEROED = {0x00};
|
||||
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};
|
||||
|
||||
public SocksV5CmdResponse(SocksV5CmdStatus cmdStatus, SocksV5AddressType addressType) {
|
||||
this(cmdStatus, addressType, null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new response and includes provided host and port as part of it.
|
||||
*
|
||||
* @param cmdStatus status of the response
|
||||
* @param addressType type of host parameter
|
||||
* @param host host (BND.ADDR field) is address that server used when connecting to the target host.
|
||||
* When null a value of 4/8 0x00 octets will be used for IPv4/IPv6 and a single 0x00 byte will be
|
||||
* used for domain addressType. Value is converted to ASCII using {@link IDN#toASCII(String)}.
|
||||
* @param port port (BND.PORT field) that the server assigned to connect to the target host
|
||||
* @throws NullPointerException in case cmdStatus or addressType are missing
|
||||
* @throws IllegalArgumentException in case host or port cannot be validated
|
||||
* @see IDN#toASCII(String)
|
||||
*/
|
||||
public SocksV5CmdResponse(SocksV5CmdStatus cmdStatus, SocksV5AddressType addressType, String host, int port) {
|
||||
super(SocksV5ResponseType.CMD);
|
||||
if (cmdStatus == null) {
|
||||
throw new NullPointerException("cmdStatus");
|
||||
}
|
||||
if (addressType == null) {
|
||||
throw new NullPointerException("addressType");
|
||||
}
|
||||
if (host != null) {
|
||||
switch (addressType) {
|
||||
case IPv4:
|
||||
if (!NetUtil.isValidIpV4Address(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 (!NetUtil.isValidIpV6Address(host)) {
|
||||
throw new IllegalArgumentException(host + " is not a valid IPv6 address");
|
||||
}
|
||||
break;
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
host = IDN.toASCII(host);
|
||||
}
|
||||
if (port < 0 || port > 65535) {
|
||||
throw new IllegalArgumentException(port + " is not in bounds 0 <= x <= 65535");
|
||||
}
|
||||
this.cmdStatus = cmdStatus;
|
||||
this.addressType = addressType;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocksV5CmdStatus} of this {@link SocksV5CmdResponse}
|
||||
*
|
||||
* @return The {@link SocksV5CmdStatus} of this {@link SocksV5CmdResponse}
|
||||
*/
|
||||
public SocksV5CmdStatus cmdStatus() {
|
||||
return cmdStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocksV5AddressType} of this {@link SocksV5CmdResponse}
|
||||
*
|
||||
* @return The {@link SocksV5AddressType} of this {@link SocksV5CmdResponse}
|
||||
*/
|
||||
public SocksV5AddressType addressType() {
|
||||
return addressType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns host that is used as a parameter in {@link SocksV5CmdType}.
|
||||
* Host (BND.ADDR field in response) is address that server used when connecting to the target host.
|
||||
* This is typically different from address which client uses to connect to the SOCKS server.
|
||||
*
|
||||
* @return host that is used as a parameter in {@link SocksV5CmdType}
|
||||
* or null when there was no host specified during response construction
|
||||
*/
|
||||
public String host() {
|
||||
if (host != null) {
|
||||
return IDN.toUnicode(host);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns port that is used as a parameter in {@link SocksV5CmdType}.
|
||||
* Port (BND.PORT field in response) is port that the server assigned to connect to the target host.
|
||||
*
|
||||
* @return port that is used as a parameter in {@link SocksV5CmdType}
|
||||
*/
|
||||
public int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(protocolVersion().byteValue());
|
||||
byteBuf.writeByte(cmdStatus.byteValue());
|
||||
byteBuf.writeByte(0x00);
|
||||
byteBuf.writeByte(addressType.byteValue());
|
||||
switch (addressType) {
|
||||
case IPv4: {
|
||||
byte[] hostContent = host == null ?
|
||||
IPv4_HOSTNAME_ZEROED : NetUtil.createByteArrayFromIpAddressString(host);
|
||||
byteBuf.writeBytes(hostContent);
|
||||
byteBuf.writeShort(port);
|
||||
break;
|
||||
}
|
||||
case DOMAIN: {
|
||||
byte[] hostContent = host == null ?
|
||||
DOMAIN_ZEROED : host.getBytes(CharsetUtil.US_ASCII);
|
||||
byteBuf.writeByte(hostContent.length); // domain length
|
||||
byteBuf.writeBytes(hostContent); // domain value
|
||||
byteBuf.writeShort(port); // port value
|
||||
break;
|
||||
}
|
||||
case IPv6: {
|
||||
byte[] hostContent = host == null
|
||||
? IPv6_HOSTNAME_ZEROED : NetUtil.createByteArrayFromIpAddressString(host);
|
||||
byteBuf.writeBytes(hostContent);
|
||||
byteBuf.writeShort(port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdResponseDecoder.State;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksV5CmdResponse}.
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksV5CmdResponseDecoder extends ReplayingDecoder<State> {
|
||||
private SocksProtocolVersion version;
|
||||
private int fieldLength;
|
||||
private SocksV5CmdStatus cmdStatus;
|
||||
private SocksV5AddressType addressType;
|
||||
private byte reserved;
|
||||
private String host;
|
||||
private int port;
|
||||
private SocksV5Response msg = UnknownSocksV5Response.getInstance();
|
||||
|
||||
public SocksV5CmdResponseDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksProtocolVersion.valueOf(byteBuf.readByte());
|
||||
if (version != SocksProtocolVersion.SOCKS5) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_CMD_HEADER);
|
||||
}
|
||||
case READ_CMD_HEADER: {
|
||||
cmdStatus = SocksV5CmdStatus.valueOf(byteBuf.readByte());
|
||||
reserved = byteBuf.readByte();
|
||||
addressType = SocksV5AddressType.valueOf(byteBuf.readByte());
|
||||
checkpoint(State.READ_CMD_ADDRESS);
|
||||
}
|
||||
case READ_CMD_ADDRESS: {
|
||||
switch (addressType) {
|
||||
case IPv4: {
|
||||
host = SocksV5CommonUtils.intToIp(byteBuf.readInt());
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksV5CmdResponse(cmdStatus, addressType, host, port);
|
||||
break;
|
||||
}
|
||||
case DOMAIN: {
|
||||
fieldLength = byteBuf.readByte();
|
||||
host = byteBuf.readBytes(fieldLength).toString(CharsetUtil.US_ASCII);
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksV5CmdResponse(cmdStatus, addressType, host, port);
|
||||
break;
|
||||
}
|
||||
case IPv6: {
|
||||
host = SocksV5CommonUtils.ipv6toStr(byteBuf.readBytes(16).array());
|
||||
port = byteBuf.readUnsignedShort();
|
||||
msg = new SocksV5CmdResponse(cmdStatus, addressType, host, port);
|
||||
break;
|
||||
}
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
out.add(msg);
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_CMD_HEADER,
|
||||
READ_CMD_ADDRESS
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx.v5;
|
||||
|
||||
public enum SocksV5CmdStatus {
|
||||
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;
|
||||
|
||||
SocksV5CmdStatus(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static SocksV5CmdStatus valueOf(byte b) {
|
||||
for (SocksV5CmdStatus code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNASSIGNED;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return b;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx.v5;
|
||||
|
||||
public enum SocksV5CmdType {
|
||||
CONNECT((byte) 0x01),
|
||||
BIND((byte) 0x02),
|
||||
UDP((byte) 0x03),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
SocksV5CmdType(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static SocksV5CmdType valueOf(byte b) {
|
||||
for (SocksV5CmdType code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
public final class SocksV5CommonUtils {
|
||||
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 SocksV5CommonUtils() {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
public static String intToIp(int i) {
|
||||
return String.valueOf(i >> FIRST_ADDRESS_OCTET_SHIFT & XOR_DEFAULT_VALUE) + '.' +
|
||||
(i >> SECOND_ADDRESS_OCTET_SHIFT & XOR_DEFAULT_VALUE) + '.' +
|
||||
(i >> THIRD_ADDRESS_OCTET_SHIFT & XOR_DEFAULT_VALUE) + '.' +
|
||||
(i & XOR_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts numeric IPv6 to standard (non-compressed) format.
|
||||
*/
|
||||
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) {
|
||||
int i;
|
||||
toHextet --;
|
||||
for (i = fromHextet; i < toHextet; i++) {
|
||||
appendHextet(sb, src, i);
|
||||
sb.append(ipv6hextetSeparator);
|
||||
}
|
||||
|
||||
appendHextet(sb, src, i);
|
||||
}
|
||||
|
||||
private static void appendHextet(StringBuilder sb, byte[] src, int i) {
|
||||
StringUtil.toHexString(sb, src, i << 1, 2);
|
||||
}
|
||||
}
|
@ -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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An socks init request.
|
||||
*
|
||||
* @see SocksV5InitResponse
|
||||
* @see SocksV5InitRequestDecoder
|
||||
*/
|
||||
public final class SocksV5InitRequest extends SocksV5Request {
|
||||
private final List<SocksV5AuthScheme> authSchemes;
|
||||
|
||||
public SocksV5InitRequest(List<SocksV5AuthScheme> authSchemes) {
|
||||
super(SocksV5RequestType.INIT);
|
||||
if (authSchemes == null) {
|
||||
throw new NullPointerException("authSchemes");
|
||||
}
|
||||
this.authSchemes = authSchemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the List<{@link SocksV5AuthScheme}> of this {@link SocksV5InitRequest}
|
||||
*
|
||||
* @return The List<{@link SocksV5AuthScheme}> of this {@link SocksV5InitRequest}
|
||||
*/
|
||||
public List<SocksV5AuthScheme> authSchemes() {
|
||||
return Collections.unmodifiableList(authSchemes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(protocolVersion().byteValue());
|
||||
byteBuf.writeByte(authSchemes.size());
|
||||
for (SocksV5AuthScheme authScheme : authSchemes) {
|
||||
byteBuf.writeByte(authScheme.byteValue());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5InitRequestDecoder.State;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksV5InitRequest}.
|
||||
* Before returning SocksRequest decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksV5InitRequestDecoder extends ReplayingDecoder<State> {
|
||||
private final List<SocksV5AuthScheme> authSchemes = new ArrayList<SocksV5AuthScheme>();
|
||||
private SocksProtocolVersion version;
|
||||
private byte authSchemeNum;
|
||||
private SocksV5Request msg = UnknownSocksV5Request.getInstance();
|
||||
|
||||
public SocksV5InitRequestDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksProtocolVersion.valueOf(byteBuf.readByte());
|
||||
if (version != SocksProtocolVersion.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(SocksV5AuthScheme.valueOf(byteBuf.readByte()));
|
||||
}
|
||||
msg = new SocksV5InitRequest(authSchemes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
out.add(msg);
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_AUTH_SCHEMES
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An socks init response.
|
||||
*
|
||||
* @see SocksV5InitRequest
|
||||
* @see SocksV5InitResponseDecoder
|
||||
*/
|
||||
public final class SocksV5InitResponse extends SocksV5Response {
|
||||
private final SocksV5AuthScheme authScheme;
|
||||
|
||||
public SocksV5InitResponse(SocksV5AuthScheme authScheme) {
|
||||
super(SocksV5ResponseType.INIT);
|
||||
if (authScheme == null) {
|
||||
throw new NullPointerException("authScheme");
|
||||
}
|
||||
this.authScheme = authScheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocksV5AuthScheme} of this {@link SocksV5InitResponse}
|
||||
*
|
||||
* @return The {@link SocksV5AuthScheme} of this {@link SocksV5InitResponse}
|
||||
*/
|
||||
public SocksV5AuthScheme authScheme() {
|
||||
return authScheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
byteBuf.writeByte(protocolVersion().byteValue());
|
||||
byteBuf.writeByte(authScheme.byteValue());
|
||||
}
|
||||
}
|
@ -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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5InitResponseDecoder.State;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Decodes {@link ByteBuf}s into {@link SocksV5InitResponse}.
|
||||
* Before returning SocksResponse decoder removes itself from pipeline.
|
||||
*/
|
||||
public class SocksV5InitResponseDecoder extends ReplayingDecoder<State> {
|
||||
private SocksProtocolVersion version;
|
||||
private SocksV5AuthScheme authScheme;
|
||||
|
||||
private SocksV5Response msg = UnknownSocksV5Response.getInstance();
|
||||
|
||||
public SocksV5InitResponseDecoder() {
|
||||
super(State.CHECK_PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
|
||||
switch (state()) {
|
||||
case CHECK_PROTOCOL_VERSION: {
|
||||
version = SocksProtocolVersion.valueOf(byteBuf.readByte());
|
||||
if (version != SocksProtocolVersion.SOCKS5) {
|
||||
break;
|
||||
}
|
||||
checkpoint(State.READ_PREFFERED_AUTH_TYPE);
|
||||
}
|
||||
case READ_PREFFERED_AUTH_TYPE: {
|
||||
authScheme = SocksV5AuthScheme.valueOf(byteBuf.readByte());
|
||||
msg = new SocksV5InitResponse(authScheme);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx.pipeline().remove(this);
|
||||
out.add(msg);
|
||||
}
|
||||
|
||||
enum State {
|
||||
CHECK_PROTOCOL_VERSION,
|
||||
READ_PREFFERED_AUTH_TYPE
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.handler.codec.socksx.SocksMessage;
|
||||
import io.netty.handler.codec.socksx.SocksMessageType;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.SocksRequest;
|
||||
|
||||
/**
|
||||
* An abstract class that defines a SocksRequest, providing common properties for
|
||||
* {@link SocksV5InitRequest},
|
||||
* {@link SocksV5AuthRequest},
|
||||
* {@link SocksV5CmdRequest} and
|
||||
* {@link UnknownSocksV5Request}.
|
||||
*
|
||||
* @see SocksV5InitRequest
|
||||
* @see SocksV5AuthRequest
|
||||
* @see SocksV5CmdRequest
|
||||
* @see UnknownSocksV5Request
|
||||
*/
|
||||
public abstract class SocksV5Request extends SocksRequest {
|
||||
private final SocksV5RequestType requestType;
|
||||
|
||||
protected SocksV5Request(SocksV5RequestType requestType) {
|
||||
super(SocksProtocolVersion.SOCKS5);
|
||||
if (requestType == null) {
|
||||
throw new NullPointerException("requestType");
|
||||
}
|
||||
this.requestType = requestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns socks request type
|
||||
*
|
||||
* @return socks request type
|
||||
*/
|
||||
public SocksV5RequestType requestType() {
|
||||
return requestType;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx.v5;
|
||||
|
||||
/**
|
||||
* Type of socks request
|
||||
*/
|
||||
public enum SocksV5RequestType {
|
||||
INIT,
|
||||
AUTH,
|
||||
CMD,
|
||||
UNKNOWN
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.handler.codec.socksx.SocksMessage;
|
||||
import io.netty.handler.codec.socksx.SocksMessageType;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.SocksResponse;
|
||||
|
||||
/**
|
||||
* An abstract class that defines a SocksResponse, providing common properties for
|
||||
* {@link SocksV5InitResponse},
|
||||
* {@link SocksV5AuthResponse},
|
||||
* {@link SocksV5CmdResponse}
|
||||
* and {@link UnknownSocksV5Response}.
|
||||
*
|
||||
* @see SocksV5InitResponse
|
||||
* @see SocksV5AuthResponse
|
||||
* @see SocksV5CmdResponse
|
||||
* @see UnknownSocksV5Response
|
||||
*/
|
||||
public abstract class SocksV5Response extends SocksResponse {
|
||||
private final SocksV5ResponseType responseType;
|
||||
|
||||
protected SocksV5Response(SocksV5ResponseType responseType) {
|
||||
super(SocksProtocolVersion.SOCKS5);
|
||||
if (responseType == null) {
|
||||
throw new NullPointerException("responseType");
|
||||
}
|
||||
this.responseType = responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns socks response type
|
||||
*
|
||||
* @return socks response type
|
||||
*/
|
||||
public SocksV5ResponseType responseType() {
|
||||
return responseType;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx.v5;
|
||||
|
||||
/**
|
||||
* Type of socks response
|
||||
*/
|
||||
public enum SocksV5ResponseType {
|
||||
INIT,
|
||||
AUTH,
|
||||
CMD,
|
||||
UNKNOWN
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2013 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.handler.codec.socksx.v5;
|
||||
|
||||
public enum SocksV5SubnegotiationVersion {
|
||||
AUTH_PASSWORD((byte) 0x01),
|
||||
UNKNOWN((byte) 0xff);
|
||||
|
||||
private final byte b;
|
||||
|
||||
SocksV5SubnegotiationVersion(byte b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static SocksV5SubnegotiationVersion valueOf(byte b) {
|
||||
for (SocksV5SubnegotiationVersion code : values()) {
|
||||
if (code.b == b) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
@ -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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An unknown socks request.
|
||||
*
|
||||
* @see SocksV5InitRequestDecoder
|
||||
* @see SocksV5AuthRequestDecoder
|
||||
* @see SocksV5CmdRequestDecoder
|
||||
*/
|
||||
public final class UnknownSocksV5Request extends SocksV5Request {
|
||||
|
||||
public UnknownSocksV5Request() {
|
||||
super(SocksV5RequestType.UNKNOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
private static class UnknownSocksV5RequestHolder {
|
||||
public static final UnknownSocksV5Request HOLDER_INSTANCE = new UnknownSocksV5Request();
|
||||
}
|
||||
|
||||
public static UnknownSocksV5Request getInstance() {
|
||||
return UnknownSocksV5RequestHolder.HOLDER_INSTANCE;
|
||||
}
|
||||
}
|
@ -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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* An unknown socks response.
|
||||
*
|
||||
* @see SocksV5InitResponseDecoder
|
||||
* @see SocksV5AuthResponseDecoder
|
||||
* @see SocksV5CmdResponseDecoder
|
||||
*/
|
||||
public final class UnknownSocksV5Response extends SocksV5Response {
|
||||
|
||||
public UnknownSocksV5Response() {
|
||||
super(SocksV5ResponseType.UNKNOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encodeAsByteBuf(ByteBuf byteBuf) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
private static class UnknownSocksV5ResponseHolder {
|
||||
public static final UnknownSocksV5Response HOLDER_INSTANCE = new UnknownSocksV5Response();
|
||||
}
|
||||
|
||||
public static UnknownSocksV5Response getInstance() {
|
||||
return UnknownSocksV5ResponseHolder.HOLDER_INSTANCE;
|
||||
}
|
||||
}
|
21
codec-socks/src/main/java/io/netty/handler/codec/socksx/v5/package-info.java
Executable file
21
codec-socks/src/main/java/io/netty/handler/codec/socksx/v5/package-info.java
Executable file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
// TODO: Combine decoders into one.
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5AddressType;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdRequest;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdType;
|
||||
import io.netty.handler.codec.socksx.v5.UnknownSocksV5Request;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksV4CmdRequestDecoderTest {
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(SocksV4CmdRequestDecoderTest.class);
|
||||
|
||||
private static void testSocksV4CmdRequestDecoderWithDifferentParams(String userId,
|
||||
SocksV4CmdType cmdType,
|
||||
String host,
|
||||
int port) {
|
||||
logger.debug("Testing cmdType: " + cmdType + " userId: " + userId + " host: " + host +
|
||||
" port: " + port);
|
||||
SocksV4CmdRequest msg = new SocksV4CmdRequest(userId, cmdType, host, port);
|
||||
SocksV4CmdRequestDecoder decoder = new SocksV4CmdRequestDecoder();
|
||||
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
|
||||
SocksV4CommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
Object obj = embedder.readInbound();
|
||||
msg = (SocksV4CmdRequest) obj;
|
||||
assertSame(msg.cmdType(), cmdType);
|
||||
assertEquals(msg.userId(), userId);
|
||||
assertEquals(msg.host(), host);
|
||||
assertEquals(msg.port(), port);
|
||||
assertNull(embedder.readInbound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCmdRequestDecoder() {
|
||||
String[] hosts = {"127.0.0.1", };
|
||||
String[] userIds = {"test", };
|
||||
int[] ports = {1, 32769, 65535};
|
||||
for (SocksV4CmdType cmdType : SocksV4CmdType.values()) {
|
||||
for (String userId : userIds) {
|
||||
for (String host : hosts) {
|
||||
for (int port : ports) {
|
||||
testSocksV4CmdRequestDecoderWithDifferentParams(userId, cmdType, host, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SocksV4CmdRequestTest {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocksV4CmdRequestTest.class);
|
||||
}
|
@ -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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5AddressType;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdStatus;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksV4CmdResponseDecoderTest {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocksV4CmdResponseDecoderTest.class);
|
||||
|
||||
private static void testSocksCmdResponseDecoderWithDifferentParams(
|
||||
SocksV4CmdStatus cmdStatus, String host, int port) {
|
||||
logger.debug("Testing cmdStatus: " + cmdStatus);
|
||||
SocksV4Response msg = new SocksV4CmdResponse(cmdStatus, host, port);
|
||||
SocksV4CmdResponseDecoder decoder = new SocksV4CmdResponseDecoder();
|
||||
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
|
||||
SocksV4CommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
|
||||
msg = (SocksV4Response) embedder.readInbound();
|
||||
assertEquals(((SocksV4CmdResponse) msg).cmdStatus(), cmdStatus);
|
||||
if (host != null) {
|
||||
assertEquals(((SocksV4CmdResponse) msg).host(), host);
|
||||
}
|
||||
assertEquals(((SocksV4CmdResponse) msg).port(), port);
|
||||
assertNull(embedder.readInbound());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that sent socks messages are decoded correctly.
|
||||
*/
|
||||
@Test
|
||||
public void testSocksCmdResponseDecoder() {
|
||||
for (SocksV4CmdStatus cmdStatus : SocksV4CmdStatus.values()) {
|
||||
testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, null, 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v4;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SocksV4CmdResponseTest {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocksV4CmdResponseTest.class);
|
||||
}
|
@ -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.handler.codec.socksx.v4;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.socksx.SocksMessage;
|
||||
|
||||
final class SocksV4CommonTestUtils {
|
||||
/**
|
||||
* A constructor to stop this class being constructed.
|
||||
*/
|
||||
private SocksV4CommonTestUtils() {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void writeMessageIntoEmbedder(EmbeddedChannel embedder, SocksMessage msg) {
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
msg.encodeAsByteBuf(buf);
|
||||
embedder.writeInbound(buf);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SocksV5AuthRequestDecoderTest {
|
||||
|
||||
@Test
|
||||
public void testAuthRequestDecoder() {
|
||||
String username = "test";
|
||||
String password = "test";
|
||||
SocksV5AuthRequest msg = new SocksV5AuthRequest(username, password);
|
||||
SocksV5AuthRequestDecoder decoder = new SocksV5AuthRequestDecoder();
|
||||
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
|
||||
SocksV5CommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
msg = (SocksV5AuthRequest) embedder.readInbound();
|
||||
assertEquals(msg.username(), username);
|
||||
assertEquals(msg.username(), 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.handler.codec.socksx.v5;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksV5AuthRequestTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksV5AuthRequest(null, "");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
try {
|
||||
new SocksV5AuthRequest("", null);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernameOrPasswordIsNotAscii() {
|
||||
try {
|
||||
new SocksV5AuthRequest("παράδειγμα.δοκιμή", "password");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
try {
|
||||
new SocksV5AuthRequest("username", "παράδειγμα.δοκιμή");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernameOrPasswordLengthIsLessThan255Chars() {
|
||||
try {
|
||||
new SocksV5AuthRequest(
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword",
|
||||
"password");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
try {
|
||||
new SocksV5AuthRequest("password",
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword" +
|
||||
"passwordpasswordpasswordpasswordpasswordpasswordpassword");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SocksV5AuthResponseDecoderTest {
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(
|
||||
SocksV5AuthResponseDecoderTest.class);
|
||||
|
||||
private static void testSocksAuthResponseDecoderWithDifferentParams(SocksV5AuthStatus authStatus) {
|
||||
logger.debug("Testing SocksAuthResponseDecoder with authStatus: " + authStatus);
|
||||
SocksV5AuthResponse msg = new SocksV5AuthResponse(authStatus);
|
||||
SocksV5AuthResponseDecoder decoder = new SocksV5AuthResponseDecoder();
|
||||
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
|
||||
SocksV5CommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
msg = (SocksV5AuthResponse) embedder.readInbound();
|
||||
assertSame(msg.authStatus(), authStatus);
|
||||
assertNull(embedder.readInbound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSocksCmdResponseDecoder() {
|
||||
for (SocksV5AuthStatus authStatus: SocksV5AuthStatus.values()) {
|
||||
testSocksAuthResponseDecoderWithDifferentParams(authStatus);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksV5AuthResponseTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksV5AuthResponse(null);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import org.junit.Test;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SocksV5CmdRequestDecoderTest {
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(SocksV5CmdRequestDecoderTest.class);
|
||||
|
||||
private static void testSocksCmdRequestDecoderWithDifferentParams(SocksV5CmdType cmdType,
|
||||
SocksV5AddressType addressType,
|
||||
String host,
|
||||
int port) {
|
||||
logger.debug("Testing cmdType: " + cmdType + " addressType: " + addressType + " host: " + host +
|
||||
" port: " + port);
|
||||
SocksV5CmdRequest msg = new SocksV5CmdRequest(cmdType, addressType, host, port);
|
||||
SocksV5CmdRequestDecoder decoder = new SocksV5CmdRequestDecoder();
|
||||
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
|
||||
SocksV5CommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
if (msg.addressType() == SocksV5AddressType.UNKNOWN) {
|
||||
assertTrue(embedder.readInbound() instanceof UnknownSocksV5Request);
|
||||
} else {
|
||||
msg = (SocksV5CmdRequest) embedder.readInbound();
|
||||
assertSame(msg.cmdType(), cmdType);
|
||||
assertSame(msg.addressType(), addressType);
|
||||
assertEquals(msg.host(), host);
|
||||
assertEquals(msg.port(), port);
|
||||
}
|
||||
assertNull(embedder.readInbound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCmdRequestDecoderIPv4() {
|
||||
String[] hosts = {"127.0.0.1", };
|
||||
int[] ports = {1, 32769, 65535 };
|
||||
for (SocksV5CmdType cmdType : SocksV5CmdType.values()) {
|
||||
for (String host : hosts) {
|
||||
for (int port : ports) {
|
||||
testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksV5AddressType.IPv4, host, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCmdRequestDecoderIPv6() {
|
||||
String[] hosts = {SocksV5CommonUtils.ipv6toStr(IPAddressUtil.textToNumericFormatV6("::1"))};
|
||||
int[] ports = {1, 32769, 65535};
|
||||
for (SocksV5CmdType cmdType : SocksV5CmdType.values()) {
|
||||
for (String host : hosts) {
|
||||
for (int port : ports) {
|
||||
testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksV5AddressType.IPv6, host, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCmdRequestDecoderDomain() {
|
||||
String[] hosts = {"google.com" ,
|
||||
"مثال.إختبار",
|
||||
"παράδειγμα.δοκιμή",
|
||||
"مثال.آزمایشی",
|
||||
"пример.испытание",
|
||||
"בײַשפּיל.טעסט",
|
||||
"例子.测试",
|
||||
"例子.測試",
|
||||
"उदाहरण.परीक्षा",
|
||||
"例え.テスト",
|
||||
"실례.테스트",
|
||||
"உதாரணம்.பரிட்சை"};
|
||||
int[] ports = {1, 32769, 65535};
|
||||
for (SocksV5CmdType cmdType : SocksV5CmdType.values()) {
|
||||
for (String host : hosts) {
|
||||
for (int port : ports) {
|
||||
testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksV5AddressType.DOMAIN, host, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCmdRequestDecoderUnknown() {
|
||||
String host = "google.com";
|
||||
int port = 80;
|
||||
for (SocksV5CmdType cmdType : SocksV5CmdType.values()) {
|
||||
testSocksCmdRequestDecoderWithDifferentParams(cmdType, SocksV5AddressType.UNKNOWN, host, port);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SocksV5CmdRequestTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksV5CmdRequest(null, SocksV5AddressType.UNKNOWN, "", 1);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
|
||||
try {
|
||||
new SocksV5CmdRequest(SocksV5CmdType.UNKNOWN, null, "", 1);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
|
||||
try {
|
||||
new SocksV5CmdRequest(SocksV5CmdType.UNKNOWN, SocksV5AddressType.UNKNOWN, null, 1);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPv4CorrectAddress() {
|
||||
try {
|
||||
new SocksV5CmdRequest(SocksV5CmdType.BIND, SocksV5AddressType.IPv4, "54.54.1111.253", 1);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIPv6CorrectAddress() {
|
||||
try {
|
||||
new SocksV5CmdRequest(SocksV5CmdType.BIND, SocksV5AddressType.IPv6, "xxx:xxx:xxx", 1);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIDNNotExceeds255CharsLimit() {
|
||||
try {
|
||||
new SocksV5CmdRequest(SocksV5CmdType.BIND, SocksV5AddressType.DOMAIN,
|
||||
"παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" +
|
||||
"παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" +
|
||||
"παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή" +
|
||||
"παράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμήπαράδειγμα.δοκιμή", 1);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidPortRange() {
|
||||
try {
|
||||
new SocksV5CmdRequest(SocksV5CmdType.BIND, SocksV5AddressType.DOMAIN,
|
||||
"παράδειγμα.δοκιμήπαράδει", 0);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
|
||||
try {
|
||||
new SocksV5CmdRequest(SocksV5CmdType.BIND, SocksV5AddressType.DOMAIN,
|
||||
"παράδειγμα.δοκιμήπαράδει", 65536);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SocksV5CmdResponseDecoderTest {
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(SocksV5CmdResponseDecoderTest.class);
|
||||
|
||||
private static void testSocksCmdResponseDecoderWithDifferentParams(
|
||||
SocksV5CmdStatus cmdStatus, SocksV5AddressType addressType, String host, int port) {
|
||||
logger.debug("Testing cmdStatus: " + cmdStatus + " addressType: " + addressType);
|
||||
SocksV5Response msg = new SocksV5CmdResponse(cmdStatus, addressType, host, port);
|
||||
SocksV5CmdResponseDecoder decoder = new SocksV5CmdResponseDecoder();
|
||||
EmbeddedChannel embedder = new EmbeddedChannel(decoder);
|
||||
SocksV5CommonTestUtils.writeMessageIntoEmbedder(embedder, msg);
|
||||
if (addressType == SocksV5AddressType.UNKNOWN) {
|
||||
assertTrue(embedder.readInbound() instanceof UnknownSocksV5Response);
|
||||
} else {
|
||||
msg = (SocksV5Response) embedder.readInbound();
|
||||
assertEquals(((SocksV5CmdResponse) msg).cmdStatus(), cmdStatus);
|
||||
if (host != null) {
|
||||
assertEquals(((SocksV5CmdResponse) msg).host(), host);
|
||||
}
|
||||
assertEquals(((SocksV5CmdResponse) msg).port(), port);
|
||||
}
|
||||
assertNull(embedder.readInbound());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that sent socks messages are decoded correctly.
|
||||
*/
|
||||
@Test
|
||||
public void testSocksCmdResponseDecoder() {
|
||||
for (SocksV5CmdStatus cmdStatus : SocksV5CmdStatus.values()) {
|
||||
for (SocksV5AddressType addressType : SocksV5AddressType.values()) {
|
||||
testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, addressType, null, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that invalid bound host will fail with IllegalArgumentException during encoding.
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testInvalidAddress() {
|
||||
testSocksCmdResponseDecoderWithDifferentParams(SocksV5CmdStatus.SUCCESS, SocksV5AddressType.IPv4, "1", 80);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that send socks messages are decoded correctly when bound host and port are set.
|
||||
*/
|
||||
@Test
|
||||
public void testSocksCmdResponseDecoderIncludingHost() {
|
||||
for (SocksV5CmdStatus cmdStatus : SocksV5CmdStatus.values()) {
|
||||
testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, SocksV5AddressType.IPv4,
|
||||
"127.0.0.1", 80);
|
||||
testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, SocksV5AddressType.DOMAIN,
|
||||
"testDomain.com", 80);
|
||||
testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, SocksV5AddressType.IPv6,
|
||||
"2001:db8:85a3:42:1000:8a2e:370:7334", 80);
|
||||
testSocksCmdResponseDecoderWithDifferentParams(cmdStatus, SocksV5AddressType.IPv6,
|
||||
"1111:111:11:1:0:0:0:1", 80);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SocksV5CmdResponseTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksV5CmdResponse(null, SocksV5AddressType.UNKNOWN);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
try {
|
||||
new SocksV5CmdResponse(SocksV5CmdStatus.UNASSIGNED, null);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies content of the response when domain is not specified.
|
||||
*/
|
||||
@Test
|
||||
public void testEmptyDomain() {
|
||||
SocksV5CmdResponse socksV5CmdResponse = new SocksV5CmdResponse(
|
||||
SocksV5CmdStatus.SUCCESS, SocksV5AddressType.DOMAIN);
|
||||
assertNull(socksV5CmdResponse.host());
|
||||
assertEquals(0, socksV5CmdResponse.port());
|
||||
ByteBuf buffer = Unpooled.buffer(20);
|
||||
socksV5CmdResponse.encodeAsByteBuf(buffer);
|
||||
byte[] expected = {
|
||||
0x05, // version
|
||||
0x00, // success reply
|
||||
0x00, // reserved
|
||||
0x03, // address type domain
|
||||
0x01, // length of domain
|
||||
0x00, // domain value
|
||||
0x00, // port value
|
||||
0x00
|
||||
};
|
||||
assertByteBufEquals(expected, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies content of the response when IPv4 address is specified.
|
||||
*/
|
||||
@Test
|
||||
public void testIPv4Host() {
|
||||
SocksV5CmdResponse socksV5CmdResponse = new SocksV5CmdResponse(
|
||||
SocksV5CmdStatus.SUCCESS, SocksV5AddressType.IPv4, "127.0.0.1", 80);
|
||||
assertEquals("127.0.0.1", socksV5CmdResponse.host());
|
||||
assertEquals(80, socksV5CmdResponse.port());
|
||||
ByteBuf buffer = Unpooled.buffer(20);
|
||||
socksV5CmdResponse.encodeAsByteBuf(buffer);
|
||||
byte[] expected = {
|
||||
0x05, // version
|
||||
0x00, // success reply
|
||||
0x00, // reserved
|
||||
0x01, // address type IPv4
|
||||
0x7F, // address 127.0.0.1
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x00, // port
|
||||
0x50
|
||||
};
|
||||
assertByteBufEquals(expected, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that empty domain is allowed Response.
|
||||
*/
|
||||
@Test
|
||||
public void testEmptyBoundAddress() {
|
||||
SocksV5CmdResponse socksV5CmdResponse = new SocksV5CmdResponse(
|
||||
SocksV5CmdStatus.SUCCESS, SocksV5AddressType.DOMAIN, "", 80);
|
||||
assertEquals("", socksV5CmdResponse.host());
|
||||
assertEquals(80, socksV5CmdResponse.port());
|
||||
ByteBuf buffer = Unpooled.buffer(20);
|
||||
socksV5CmdResponse.encodeAsByteBuf(buffer);
|
||||
byte[] expected = {
|
||||
0x05, // version
|
||||
0x00, // success reply
|
||||
0x00, // reserved
|
||||
0x03, // address type domain
|
||||
0x00, // domain length
|
||||
0x00, // port
|
||||
0x50
|
||||
};
|
||||
assertByteBufEquals(expected, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that Response cannot be constructed with invalid IP.
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testInvalidBoundAddress() {
|
||||
new SocksV5CmdResponse(SocksV5CmdStatus.SUCCESS, SocksV5AddressType.IPv4, "127.0.0", 1000);
|
||||
}
|
||||
|
||||
private static void assertByteBufEquals(byte[] expected, ByteBuf actual) {
|
||||
byte[] actualBytes = new byte[actual.readableBytes()];
|
||||
actual.readBytes(actualBytes);
|
||||
assertEquals("Generated response has incorrect length", expected.length, actualBytes.length);
|
||||
assertArrayEquals("Generated response differs from expected", expected, actualBytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidPortRange() {
|
||||
try {
|
||||
new SocksV5CmdResponse(SocksV5CmdStatus.SUCCESS, SocksV5AddressType.IPv4, "127.0.0", 0);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
|
||||
try {
|
||||
new SocksV5CmdResponse(SocksV5CmdStatus.SUCCESS, SocksV5AddressType.IPv4, "127.0.0", 65536);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
}
|
@ -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.handler.codec.socksx.v5;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.socksx.SocksMessage;
|
||||
|
||||
final class SocksV5CommonTestUtils {
|
||||
/**
|
||||
* A constructor to stop this class being constructed.
|
||||
*/
|
||||
private SocksV5CommonTestUtils() {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void writeMessageIntoEmbedder(EmbeddedChannel 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.handler.codec.socksx.v5;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksV5InitRequestTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksV5InitRequest(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.handler.codec.socksx.v5;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SocksV5InitResponseTest {
|
||||
@Test
|
||||
public void testConstructorParamsAreNotNull() {
|
||||
try {
|
||||
new SocksV5InitResponse(null);
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof NullPointerException);
|
||||
}
|
||||
}
|
||||
}
|
@ -76,7 +76,7 @@
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-tcnative</artifactId>
|
||||
<classifier>${os.detected.classifier}</classifier>
|
||||
<classifier>${os.detected.classifier}</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.npn</groupId>
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.ChannelPipeline;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.socksx.SocksMessageEncoder;
|
||||
import io.netty.handler.codec.socksx.SocksProtocolVersion;
|
||||
import io.netty.handler.codec.socksx.v4.SocksV4CmdRequestDecoder;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5InitRequestDecoder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SocksPortUnificationServerHandler extends ByteToMessageDecoder {
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
ChannelPipeline p = ctx.pipeline();
|
||||
SocksProtocolVersion version = SocksProtocolVersion.valueOf(in.readByte());
|
||||
System.out.println(version);
|
||||
in.resetReaderIndex();
|
||||
switch (version) {
|
||||
case SOCKS4a:
|
||||
p.addLast(new SocksV4CmdRequestDecoder());
|
||||
break;
|
||||
case SOCKS5:
|
||||
p.addLast(new SocksV5InitRequestDecoder());
|
||||
break;
|
||||
case UNKNOWN:
|
||||
in.clear();
|
||||
ctx.close();
|
||||
return;
|
||||
}
|
||||
p.addLast(SocksMessageEncoder.getInstance());
|
||||
p.addLast(SocksServerHandler.getInstance());
|
||||
p.remove(this);
|
||||
}
|
||||
}
|
@ -27,61 +27,124 @@ import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.socks.SocksCmdRequest;
|
||||
import io.netty.handler.codec.socks.SocksCmdResponse;
|
||||
import io.netty.handler.codec.socks.SocksCmdStatus;
|
||||
import io.netty.handler.codec.socksx.SocksMessage;
|
||||
import io.netty.handler.codec.socksx.SocksRequest;
|
||||
import io.netty.handler.codec.socksx.v4.SocksV4CmdRequest;
|
||||
import io.netty.handler.codec.socksx.v4.SocksV4CmdResponse;
|
||||
import io.netty.handler.codec.socksx.v4.SocksV4CmdStatus;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdRequest;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdResponse;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdStatus;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
import io.netty.util.concurrent.Promise;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public final class SocksServerConnectHandler extends SimpleChannelInboundHandler<SocksCmdRequest> {
|
||||
public final class SocksServerConnectHandler extends SimpleChannelInboundHandler<SocksRequest> {
|
||||
|
||||
private final Bootstrap b = new Bootstrap();
|
||||
|
||||
@Override
|
||||
public void messageReceived(final ChannelHandlerContext ctx, final SocksCmdRequest request) throws Exception {
|
||||
Promise<Channel> promise = ctx.executor().newPromise();
|
||||
promise.addListener(
|
||||
new GenericFutureListener<Future<Channel>>() {
|
||||
@Override
|
||||
public void operationComplete(final Future<Channel> future) throws Exception {
|
||||
final Channel outboundChannel = future.getNow();
|
||||
if (future.isSuccess()) {
|
||||
ctx.channel().writeAndFlush(new SocksCmdResponse(SocksCmdStatus.SUCCESS, request.addressType()))
|
||||
.addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture channelFuture) {
|
||||
ctx.pipeline().remove(SocksServerConnectHandler.this);
|
||||
outboundChannel.pipeline().addLast(new RelayHandler(ctx.channel()));
|
||||
ctx.pipeline().addLast(new RelayHandler(outboundChannel));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ctx.channel().writeAndFlush(new SocksCmdResponse(SocksCmdStatus.FAILURE, request.addressType()));
|
||||
SocksServerUtils.closeOnFlush(ctx.channel());
|
||||
public void messageReceived(final ChannelHandlerContext ctx, final SocksRequest message) throws Exception {
|
||||
if (message instanceof SocksV4CmdRequest) {
|
||||
final SocksV4CmdRequest request = (SocksV4CmdRequest) message;
|
||||
Promise<Channel> promise = ctx.executor().newPromise();
|
||||
promise.addListener(
|
||||
new GenericFutureListener<Future<Channel>>() {
|
||||
@Override
|
||||
public void operationComplete(final Future<Channel> future) throws Exception {
|
||||
final Channel outboundChannel = future.getNow();
|
||||
if (future.isSuccess()) {
|
||||
ctx.channel().writeAndFlush(new SocksV4CmdResponse(SocksV4CmdStatus.SUCCESS))
|
||||
.addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture channelFuture) {
|
||||
ctx.pipeline().remove(SocksServerConnectHandler.this);
|
||||
outboundChannel.pipeline().addLast(new RelayHandler(ctx.channel()));
|
||||
ctx.pipeline().addLast(new RelayHandler(outboundChannel));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ctx.channel().writeAndFlush(
|
||||
new SocksV4CmdResponse(SocksV4CmdStatus.REJECTED_OR_FAILED)
|
||||
);
|
||||
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 DirectClientHandler(promise));
|
||||
|
||||
b.connect(request.host(), request.port()).addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
// Connection established use handler provided results
|
||||
} else {
|
||||
// Close the connection if the connection attempt has failed.
|
||||
ctx.channel().writeAndFlush(
|
||||
new SocksV4CmdResponse(SocksV4CmdStatus.REJECTED_OR_FAILED)
|
||||
);
|
||||
SocksServerUtils.closeOnFlush(ctx.channel());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (message instanceof SocksV5CmdRequest) {
|
||||
final SocksV5CmdRequest request = (SocksV5CmdRequest) message;
|
||||
Promise<Channel> promise = ctx.executor().newPromise();
|
||||
promise.addListener(
|
||||
new GenericFutureListener<Future<Channel>>() {
|
||||
@Override
|
||||
public void operationComplete(final Future<Channel> future) throws Exception {
|
||||
final Channel outboundChannel = future.getNow();
|
||||
if (future.isSuccess()) {
|
||||
ctx.channel().writeAndFlush(
|
||||
new SocksV5CmdResponse(SocksV5CmdStatus.SUCCESS, request.addressType())
|
||||
).addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture channelFuture) {
|
||||
ctx.pipeline().remove(SocksServerConnectHandler.this);
|
||||
outboundChannel.pipeline().addLast(new RelayHandler(ctx.channel()));
|
||||
ctx.pipeline().addLast(new RelayHandler(outboundChannel));
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
ctx.channel().writeAndFlush(
|
||||
new SocksV5CmdResponse(SocksV5CmdStatus.FAILURE, request.addressType()));
|
||||
SocksServerUtils.closeOnFlush(ctx.channel());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
final Channel inboundChannel = 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 DirectClientHandler(promise));
|
||||
|
||||
b.group(inboundChannel.eventLoop())
|
||||
.channel(NioSocketChannel.class)
|
||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
|
||||
.option(ChannelOption.SO_KEEPALIVE, true)
|
||||
.handler(new DirectClientHandler(promise));
|
||||
|
||||
b.connect(request.host(), request.port()).addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
// Connection established use handler provided results
|
||||
} else {
|
||||
// Close the connection if the connection attempt has failed.
|
||||
ctx.channel().writeAndFlush(
|
||||
new SocksCmdResponse(SocksCmdStatus.FAILURE, request.addressType()));
|
||||
SocksServerUtils.closeOnFlush(ctx.channel());
|
||||
b.connect(request.host(), request.port()).addListener(new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
// Connection established use handler provided results
|
||||
} else {
|
||||
// Close the connection if the connection attempt has failed.
|
||||
ctx.channel().writeAndFlush(
|
||||
new SocksV5CmdResponse(SocksV5CmdStatus.FAILURE, request.addressType()));
|
||||
SocksServerUtils.closeOnFlush(ctx.channel());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,37 +18,27 @@ package io.netty.example.socksproxy;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.socks.SocksAuthResponse;
|
||||
import io.netty.handler.codec.socks.SocksAuthScheme;
|
||||
import io.netty.handler.codec.socks.SocksAuthStatus;
|
||||
import io.netty.handler.codec.socks.SocksCmdRequest;
|
||||
import io.netty.handler.codec.socks.SocksCmdRequestDecoder;
|
||||
import io.netty.handler.codec.socks.SocksCmdType;
|
||||
import io.netty.handler.codec.socks.SocksInitResponse;
|
||||
import io.netty.handler.codec.socks.SocksRequest;
|
||||
|
||||
import io.netty.handler.codec.socksx.SocksRequest;
|
||||
import io.netty.handler.codec.socksx.v4.SocksV4CmdRequest;
|
||||
import io.netty.handler.codec.socksx.v4.SocksV4CmdType;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5AuthScheme;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdRequestDecoder;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5InitResponse;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5Request;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5AuthResponse;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5AuthStatus;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdRequest;
|
||||
import io.netty.handler.codec.socksx.v5.SocksV5CmdType;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public final class SocksServerHandler extends SimpleChannelInboundHandler<SocksRequest> {
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, SocksRequest socksRequest) {
|
||||
switch (socksRequest.requestType()) {
|
||||
case INIT: {
|
||||
// auth support example
|
||||
//ctx.pipeline().addFirst(new SocksAuthRequestDecoder());
|
||||
//ctx.write(new SocksInitResponse(SocksAuthScheme.AUTH_PASSWORD));
|
||||
ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
|
||||
ctx.write(new SocksInitResponse(SocksAuthScheme.NO_AUTH));
|
||||
break;
|
||||
}
|
||||
case AUTH:
|
||||
ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
|
||||
ctx.write(new SocksAuthResponse(SocksAuthStatus.SUCCESS));
|
||||
break;
|
||||
case CMD:
|
||||
SocksCmdRequest req = (SocksCmdRequest) socksRequest;
|
||||
if (req.cmdType() == SocksCmdType.CONNECT) {
|
||||
public void messageReceived(ChannelHandlerContext ctx, SocksRequest socksRequest) throws Exception {
|
||||
switch (socksRequest.protocolVersion()) {
|
||||
case SOCKS4a:
|
||||
SocksV4CmdRequest socksV4CmdRequest = (SocksV4CmdRequest) socksRequest;
|
||||
if (socksV4CmdRequest.cmdType() == SocksV4CmdType.CONNECT) {
|
||||
ctx.pipeline().addLast(new SocksServerConnectHandler());
|
||||
ctx.pipeline().remove(this);
|
||||
ctx.fireChannelRead(socksRequest);
|
||||
@ -56,6 +46,35 @@ public final class SocksServerHandler extends SimpleChannelInboundHandler<SocksR
|
||||
ctx.close();
|
||||
}
|
||||
break;
|
||||
case SOCKS5:
|
||||
switch (((SocksV5Request) socksRequest).requestType()) {
|
||||
case INIT: {
|
||||
// auth support example
|
||||
//ctx.pipeline().addFirst(new SocksV5AuthRequestDecoder());
|
||||
//ctx.write(new SocksV5InitResponse(SocksV5AuthScheme.AUTH_PASSWORD));
|
||||
ctx.pipeline().addFirst(new SocksV5CmdRequestDecoder());
|
||||
ctx.write(new SocksV5InitResponse(SocksV5AuthScheme.NO_AUTH));
|
||||
break;
|
||||
}
|
||||
case AUTH:
|
||||
ctx.pipeline().addFirst(new SocksV5CmdRequestDecoder());
|
||||
ctx.write(new SocksV5AuthResponse(SocksV5AuthStatus.SUCCESS));
|
||||
break;
|
||||
case CMD:
|
||||
SocksV5CmdRequest socksV5CmdRequest = (SocksV5CmdRequest) socksRequest;
|
||||
if (socksV5CmdRequest.cmdType() == SocksV5CmdType.CONNECT) {
|
||||
ctx.pipeline().addLast(new SocksServerConnectHandler());
|
||||
ctx.pipeline().remove(this);
|
||||
ctx.fireChannelRead(socksRequest);
|
||||
} else {
|
||||
ctx.close();
|
||||
}
|
||||
break;
|
||||
case UNKNOWN:
|
||||
ctx.close();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case UNKNOWN:
|
||||
ctx.close();
|
||||
break;
|
||||
@ -72,4 +91,12 @@ public final class SocksServerHandler extends SimpleChannelInboundHandler<SocksR
|
||||
throwable.printStackTrace();
|
||||
SocksServerUtils.closeOnFlush(ctx.channel());
|
||||
}
|
||||
|
||||
private static class SocksServerHandlerHolder {
|
||||
public static final SocksServerHandler HOLDER_INSTANCE = new SocksServerHandler();
|
||||
}
|
||||
|
||||
public static SocksServerHandler getInstance() {
|
||||
return SocksServerHandlerHolder.HOLDER_INSTANCE;
|
||||
}
|
||||
}
|
||||
|
@ -18,19 +18,14 @@ package io.netty.example.socksproxy;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.socks.SocksInitRequestDecoder;
|
||||
import io.netty.handler.codec.socks.SocksMessageEncoder;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
|
||||
public final class SocksServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private final SocksMessageEncoder socksMessageEncoder = new SocksMessageEncoder();
|
||||
private final SocksServerHandler socksServerHandler = new SocksServerHandler();
|
||||
|
||||
@Override
|
||||
public void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
ChannelPipeline p = socketChannel.pipeline();
|
||||
p.addLast(new SocksInitRequestDecoder());
|
||||
p.addLast(socksMessageEncoder);
|
||||
p.addLast(socksServerHandler);
|
||||
p.addFirst(new LoggingHandler(LogLevel.DEBUG));
|
||||
p.addLast(new SocksPortUnificationServerHandler());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user