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.ChannelHandler.Sharable;
22 import io.netty.channel.ChannelHandlerContext;
23 import io.netty.handler.codec.EncoderException;
24 import io.netty.handler.codec.MessageToByteEncoder;
25 import io.netty.util.internal.ObjectUtil;
26 import io.netty.util.internal.StringUtil;
27
28 import java.util.List;
29 import java.util.RandomAccess;
30
31
32
33
34 @Sharable
35 public class Socks5ClientEncoder extends MessageToByteEncoder<Socks5Message> {
36
37 public static final Socks5ClientEncoder DEFAULT = new Socks5ClientEncoder();
38
39 private final Socks5AddressEncoder addressEncoder;
40
41
42
43
44 protected Socks5ClientEncoder() {
45 this(Socks5AddressEncoder.DEFAULT);
46 }
47
48
49
50
51 public Socks5ClientEncoder(Socks5AddressEncoder addressEncoder) {
52 super(Socks5Message.class);
53 this.addressEncoder = ObjectUtil.checkNotNull(addressEncoder, "addressEncoder");
54 }
55
56
57
58
59 protected final Socks5AddressEncoder addressEncoder() {
60 return addressEncoder;
61 }
62
63 @Override
64 protected void encode(ChannelHandlerContext ctx, Socks5Message msg, ByteBuf out) throws Exception {
65 if (msg instanceof Socks5InitialRequest) {
66 encodeAuthMethodRequest((Socks5InitialRequest) msg, out);
67 } else if (msg instanceof Socks5PasswordAuthRequest) {
68 encodePasswordAuthRequest((Socks5PasswordAuthRequest) msg, out);
69 } else if (msg instanceof Socks5PrivateAuthRequest) {
70 encodePrivateAuthRequest((Socks5PrivateAuthRequest) msg, out);
71 } else if (msg instanceof Socks5CommandRequest) {
72 encodeCommandRequest((Socks5CommandRequest) msg, out);
73 } else {
74 throw new EncoderException("unsupported message type: " + StringUtil.simpleClassName(msg));
75 }
76 }
77
78 private static void encodeAuthMethodRequest(Socks5InitialRequest msg, ByteBuf out) {
79 out.writeByte(msg.version().byteValue());
80
81 final List<Socks5AuthMethod> authMethods = msg.authMethods();
82 final int numAuthMethods = authMethods.size();
83 out.writeByte(numAuthMethods);
84
85 if (authMethods instanceof RandomAccess) {
86 for (int i = 0; i < numAuthMethods; i ++) {
87 out.writeByte(authMethods.get(i).byteValue());
88 }
89 } else {
90 for (Socks5AuthMethod a: authMethods) {
91 out.writeByte(a.byteValue());
92 }
93 }
94 }
95
96 private static void encodePasswordAuthRequest(Socks5PasswordAuthRequest msg, ByteBuf out) {
97 out.writeByte(0x01);
98
99 final String username = msg.username();
100 out.writeByte(username.length());
101 ByteBufUtil.writeAscii(out, username);
102
103 final String password = msg.password();
104 out.writeByte(password.length());
105 ByteBufUtil.writeAscii(out, password);
106 }
107
108 private static void encodePrivateAuthRequest(Socks5PrivateAuthRequest msg, ByteBuf out) {
109 byte[] bytes = msg.privateToken();
110 out.writeByte(0x01);
111 out.writeByte(bytes.length);
112 out.writeBytes(bytes);
113 }
114
115 private void encodeCommandRequest(Socks5CommandRequest msg, ByteBuf out) throws Exception {
116 out.writeByte(msg.version().byteValue());
117 out.writeByte(msg.type().byteValue());
118 out.writeByte(0x00);
119
120 final Socks5AddressType dstAddrType = msg.dstAddrType();
121 out.writeByte(dstAddrType.byteValue());
122 addressEncoder.encodeAddress(dstAddrType, msg.dstAddr(), out);
123 ByteBufUtil.writeShortBE(out, msg.dstPort());
124 }
125 }