1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.handler.codec.socksx.v5;
18
19 import io.netty.buffer.ByteBuf;
20 import io.netty.buffer.ByteBufUtil;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.handler.codec.DecoderException;
23 import io.netty.handler.codec.DecoderResult;
24 import io.netty.handler.codec.ReplayingDecoder;
25 import io.netty.handler.codec.socksx.SocksVersion;
26 import io.netty.handler.codec.socksx.v5.Socks5CommandResponseDecoder.State;
27 import io.netty.util.internal.ObjectUtil;
28 import io.netty.util.internal.UnstableApi;
29
30 import java.util.List;
31
32
33
34
35
36
37
38 public class Socks5CommandResponseDecoder extends ReplayingDecoder<State> {
39
40 @UnstableApi
41 public enum State {
42 INIT,
43 SUCCESS,
44 FAILURE
45 }
46
47 private final Socks5AddressDecoder addressDecoder;
48
49 public Socks5CommandResponseDecoder() {
50 this(Socks5AddressDecoder.DEFAULT);
51 }
52
53 public Socks5CommandResponseDecoder(Socks5AddressDecoder addressDecoder) {
54 super(State.INIT);
55 this.addressDecoder = ObjectUtil.checkNotNull(addressDecoder, "addressDecoder");
56 }
57
58 @Override
59 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
60 try {
61 switch (state()) {
62 case INIT: {
63 final byte version = in.readByte();
64 if (version != SocksVersion.SOCKS5.byteValue()) {
65 throw new DecoderException(
66 "unsupported version: " + version + " (expected: " + SocksVersion.SOCKS5.byteValue() + ')');
67 }
68 final Socks5CommandStatus status = Socks5CommandStatus.valueOf(in.readByte());
69 in.skipBytes(1);
70 final Socks5AddressType addrType = Socks5AddressType.valueOf(in.readByte());
71 final String addr = addressDecoder.decodeAddress(addrType, in);
72 final int port = ByteBufUtil.readUnsignedShortBE(in);
73
74 out.add(new DefaultSocks5CommandResponse(status, addrType, addr, port));
75 checkpoint(State.SUCCESS);
76 }
77 case SUCCESS: {
78 int readableBytes = actualReadableBytes();
79 if (readableBytes > 0) {
80 out.add(in.readRetainedSlice(readableBytes));
81 }
82 break;
83 }
84 case FAILURE: {
85 in.skipBytes(actualReadableBytes());
86 break;
87 }
88 }
89 } catch (Exception e) {
90 fail(out, e);
91 }
92 }
93
94 private void fail(List<Object> out, Exception cause) {
95 if (!(cause instanceof DecoderException)) {
96 cause = new DecoderException(cause);
97 }
98
99 checkpoint(State.FAILURE);
100
101 Socks5Message m = new DefaultSocks5CommandResponse(
102 Socks5CommandStatus.FAILURE, Socks5AddressType.IPv4, null, 0);
103 m.setDecoderResult(DecoderResult.failure(cause));
104 out.add(m);
105 }
106 }