2012-11-07 19:54:00 +01:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-12-04 09:14:05 +01:00
|
|
|
package io.netty.handler.codec.socks;
|
2012-11-07 19:54:00 +01:00
|
|
|
|
|
|
|
import io.netty.buffer.ByteBuf;
|
|
|
|
import io.netty.channel.ChannelHandlerContext;
|
|
|
|
import io.netty.handler.codec.ReplayingDecoder;
|
2014-07-02 12:04:11 +02:00
|
|
|
import io.netty.handler.codec.socks.SocksCmdRequestDecoder.State;
|
2017-06-23 13:21:17 +02:00
|
|
|
import io.netty.util.NetUtil;
|
2012-11-07 19:54:00 +01:00
|
|
|
|
Remove MessageList from public API and change ChannelInbound/OutboundHandler accordingly
I must admit MesageList was pain in the ass. Instead of forcing a
handler always loop over the list of messages, this commit splits
messageReceived(ctx, list) into two event handlers:
- messageReceived(ctx, msg)
- mmessageReceivedLast(ctx)
When Netty reads one or more messages, messageReceived(ctx, msg) event
is triggered for each message. Once the current read operation is
finished, messageReceivedLast() is triggered to tell the handler that
the last messageReceived() was the last message in the current batch.
Similarly, for outbound, write(ctx, list) has been split into two:
- write(ctx, msg)
- flush(ctx, promise)
Instead of writing a list of message with a promise, a user is now
supposed to call write(msg) multiple times and then call flush() to
actually flush the buffered messages.
Please note that write() doesn't have a promise with it. You must call
flush() to get notified on completion. (or you can use writeAndFlush())
Other changes:
- Because MessageList is completely hidden, codec framework uses
List<Object> instead of MessageList as an output parameter.
2013-07-08 12:03:40 +02:00
|
|
|
import java.util.List;
|
|
|
|
|
2012-11-07 19:54:00 +01:00
|
|
|
/**
|
|
|
|
* Decodes {@link ByteBuf}s into {@link SocksCmdRequest}.
|
|
|
|
* Before returning SocksRequest decoder removes itself from pipeline.
|
|
|
|
*/
|
2014-07-02 12:04:11 +02:00
|
|
|
public class SocksCmdRequestDecoder extends ReplayingDecoder<State> {
|
2012-11-07 19:54:00 +01:00
|
|
|
|
2013-02-11 11:42:23 +01:00
|
|
|
private SocksCmdType cmdType;
|
|
|
|
private SocksAddressType addressType;
|
2012-11-07 19:54:00 +01:00
|
|
|
|
|
|
|
public SocksCmdRequestDecoder() {
|
|
|
|
super(State.CHECK_PROTOCOL_VERSION);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
Remove MessageList from public API and change ChannelInbound/OutboundHandler accordingly
I must admit MesageList was pain in the ass. Instead of forcing a
handler always loop over the list of messages, this commit splits
messageReceived(ctx, list) into two event handlers:
- messageReceived(ctx, msg)
- mmessageReceivedLast(ctx)
When Netty reads one or more messages, messageReceived(ctx, msg) event
is triggered for each message. Once the current read operation is
finished, messageReceivedLast() is triggered to tell the handler that
the last messageReceived() was the last message in the current batch.
Similarly, for outbound, write(ctx, list) has been split into two:
- write(ctx, msg)
- flush(ctx, promise)
Instead of writing a list of message with a promise, a user is now
supposed to call write(msg) multiple times and then call flush() to
actually flush the buffered messages.
Please note that write() doesn't have a promise with it. You must call
flush() to get notified on completion. (or you can use writeAndFlush())
Other changes:
- Because MessageList is completely hidden, codec framework uses
List<Object> instead of MessageList as an output parameter.
2013-07-08 12:03:40 +02:00
|
|
|
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
|
2012-11-07 19:54:00 +01:00
|
|
|
switch (state()) {
|
|
|
|
case CHECK_PROTOCOL_VERSION: {
|
2017-03-08 18:03:23 +01:00
|
|
|
if (byteBuf.readByte() != SocksProtocolVersion.SOCKS5.byteValue()) {
|
|
|
|
out.add(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST);
|
2019-12-04 09:31:45 +01:00
|
|
|
checkpoint(State.DONE);
|
|
|
|
return;
|
2012-11-07 19:54:00 +01:00
|
|
|
}
|
|
|
|
checkpoint(State.READ_CMD_HEADER);
|
|
|
|
}
|
|
|
|
case READ_CMD_HEADER: {
|
2014-06-24 09:34:52 +02:00
|
|
|
cmdType = SocksCmdType.valueOf(byteBuf.readByte());
|
2017-03-08 18:03:23 +01:00
|
|
|
byteBuf.skipBytes(1); // reserved
|
2014-06-24 09:34:52 +02:00
|
|
|
addressType = SocksAddressType.valueOf(byteBuf.readByte());
|
2012-11-07 19:54:00 +01:00
|
|
|
checkpoint(State.READ_CMD_ADDRESS);
|
|
|
|
}
|
|
|
|
case READ_CMD_ADDRESS: {
|
|
|
|
switch (addressType) {
|
|
|
|
case IPv4: {
|
2017-06-23 13:21:17 +02:00
|
|
|
String host = NetUtil.intToIpAddress(byteBuf.readInt());
|
2017-03-08 18:03:23 +01:00
|
|
|
int port = byteBuf.readUnsignedShort();
|
|
|
|
out.add(new SocksCmdRequest(cmdType, addressType, host, port));
|
2019-12-04 09:31:45 +01:00
|
|
|
checkpoint(State.DONE);
|
|
|
|
return;
|
2012-11-07 19:54:00 +01:00
|
|
|
}
|
|
|
|
case DOMAIN: {
|
2017-03-08 18:03:23 +01:00
|
|
|
int fieldLength = byteBuf.readByte();
|
|
|
|
String host = SocksCommonUtils.readUsAscii(byteBuf, fieldLength);
|
|
|
|
int port = byteBuf.readUnsignedShort();
|
|
|
|
out.add(new SocksCmdRequest(cmdType, addressType, host, port));
|
2019-12-04 09:31:45 +01:00
|
|
|
checkpoint(State.DONE);
|
|
|
|
return;
|
2012-11-07 19:54:00 +01:00
|
|
|
}
|
|
|
|
case IPv6: {
|
2016-04-07 10:16:26 +02:00
|
|
|
byte[] bytes = new byte[16];
|
|
|
|
byteBuf.readBytes(bytes);
|
2017-03-08 18:03:23 +01:00
|
|
|
String host = SocksCommonUtils.ipv6toStr(bytes);
|
|
|
|
int port = byteBuf.readUnsignedShort();
|
|
|
|
out.add(new SocksCmdRequest(cmdType, addressType, host, port));
|
2019-12-04 09:31:45 +01:00
|
|
|
checkpoint(State.DONE);
|
|
|
|
return;
|
2012-11-07 19:54:00 +01:00
|
|
|
}
|
2017-03-08 18:03:23 +01:00
|
|
|
case UNKNOWN: {
|
|
|
|
out.add(SocksCommonUtils.UNKNOWN_SOCKS_REQUEST);
|
2019-12-04 09:31:45 +01:00
|
|
|
checkpoint(State.DONE);
|
|
|
|
return;
|
2017-03-08 18:03:23 +01:00
|
|
|
}
|
|
|
|
default: {
|
|
|
|
throw new Error();
|
|
|
|
}
|
2012-11-07 19:54:00 +01:00
|
|
|
}
|
2017-03-08 18:03:23 +01:00
|
|
|
}
|
2019-12-04 09:31:45 +01:00
|
|
|
case DONE:
|
|
|
|
ctx.pipeline().remove(this);
|
|
|
|
return;
|
2017-03-08 18:03:23 +01:00
|
|
|
default: {
|
|
|
|
throw new Error();
|
2012-11-07 19:54:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum State {
|
|
|
|
CHECK_PROTOCOL_VERSION,
|
|
|
|
READ_CMD_HEADER,
|
2019-12-04 09:31:45 +01:00
|
|
|
READ_CMD_ADDRESS,
|
|
|
|
DONE
|
2012-11-07 19:54:00 +01:00
|
|
|
}
|
|
|
|
}
|