1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.socks;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.util.CharsetUtil;
20 import io.netty.util.NetUtil;
21
22 import java.net.IDN;
23
24
25
26
27
28
29
30 public final class SocksCmdResponse extends SocksResponse {
31 private final SocksCmdStatus cmdStatus;
32
33 private final SocksAddressType addressType;
34 private final String host;
35 private final int port;
36
37
38 private static final byte[] DOMAIN_ZEROED = {0x00};
39 private static final byte[] IPv4_HOSTNAME_ZEROED = {0x00, 0x00, 0x00, 0x00};
40 private static final byte[] IPv6_HOSTNAME_ZEROED = {0x00, 0x00, 0x00, 0x00,
41 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00,
43 0x00, 0x00, 0x00, 0x00};
44
45 public SocksCmdResponse(SocksCmdStatus cmdStatus, SocksAddressType addressType) {
46 this(cmdStatus, addressType, null, 0);
47 }
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public SocksCmdResponse(SocksCmdStatus cmdStatus, SocksAddressType addressType, String host, int port) {
63 super(SocksResponseType.CMD);
64 if (cmdStatus == null) {
65 throw new NullPointerException("cmdStatus");
66 }
67 if (addressType == null) {
68 throw new NullPointerException("addressType");
69 }
70 if (host != null) {
71 switch (addressType) {
72 case IPv4:
73 if (!NetUtil.isValidIpV4Address(host)) {
74 throw new IllegalArgumentException(host + " is not a valid IPv4 address");
75 }
76 break;
77 case DOMAIN:
78 if (IDN.toASCII(host).length() > 255) {
79 throw new IllegalArgumentException(host + " IDN: " +
80 IDN.toASCII(host) + " exceeds 255 char limit");
81 }
82 break;
83 case IPv6:
84 if (!NetUtil.isValidIpV6Address(host)) {
85 throw new IllegalArgumentException(host + " is not a valid IPv6 address");
86 }
87 break;
88 case UNKNOWN:
89 break;
90 }
91 host = IDN.toASCII(host);
92 }
93 if (port < 0 || port > 65535) {
94 throw new IllegalArgumentException(port + " is not in bounds 0 <= x <= 65535");
95 }
96 this.cmdStatus = cmdStatus;
97 this.addressType = addressType;
98 this.host = host;
99 this.port = port;
100 }
101
102
103
104
105
106
107 public SocksCmdStatus cmdStatus() {
108 return cmdStatus;
109 }
110
111
112
113
114
115
116 public SocksAddressType addressType() {
117 return addressType;
118 }
119
120
121
122
123
124
125
126
127
128 public String host() {
129 if (host != null) {
130 return IDN.toUnicode(host);
131 } else {
132 return null;
133 }
134 }
135
136
137
138
139
140
141
142 public int port() {
143 return port;
144 }
145
146 @Override
147 public void encodeAsByteBuf(ByteBuf byteBuf) {
148 byteBuf.writeByte(protocolVersion().byteValue());
149 byteBuf.writeByte(cmdStatus.byteValue());
150 byteBuf.writeByte(0x00);
151 byteBuf.writeByte(addressType.byteValue());
152 switch (addressType) {
153 case IPv4: {
154 byte[] hostContent = host == null ?
155 IPv4_HOSTNAME_ZEROED : NetUtil.createByteArrayFromIpAddressString(host);
156 byteBuf.writeBytes(hostContent);
157 byteBuf.writeShort(port);
158 break;
159 }
160 case DOMAIN: {
161 byte[] hostContent = host == null ?
162 DOMAIN_ZEROED : host.getBytes(CharsetUtil.US_ASCII);
163 byteBuf.writeByte(hostContent.length);
164 byteBuf.writeBytes(hostContent);
165 byteBuf.writeShort(port);
166 break;
167 }
168 case IPv6: {
169 byte[] hostContent = host == null
170 ? IPv6_HOSTNAME_ZEROED : NetUtil.createByteArrayFromIpAddressString(host);
171 byteBuf.writeBytes(hostContent);
172 byteBuf.writeShort(port);
173 break;
174 }
175 }
176 }
177 }