View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.socks;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.ByteBufUtil;
20  import io.netty.util.CharsetUtil;
21  import io.netty.util.NetUtil;
22  import io.netty.util.internal.ObjectUtil;
23  
24  import java.net.IDN;
25  
26  /**
27   * An socks cmd request.
28   *
29   * @see SocksCmdResponse
30   * @see SocksCmdRequestDecoder
31   */
32  public final class SocksCmdRequest extends SocksRequest {
33      private final SocksCmdType cmdType;
34      private final SocksAddressType addressType;
35      private final String host;
36      private final int port;
37  
38      public SocksCmdRequest(SocksCmdType cmdType, SocksAddressType addressType, String host, int port) {
39          super(SocksRequestType.CMD);
40          ObjectUtil.checkNotNull(cmdType, "cmdType");
41          ObjectUtil.checkNotNull(addressType, "addressType");
42          ObjectUtil.checkNotNull(host, "host");
43  
44          switch (addressType) {
45              case IPv4:
46                  if (!NetUtil.isValidIpV4Address(host)) {
47                      throw new IllegalArgumentException(host + " is not a valid IPv4 address");
48                  }
49                  break;
50              case DOMAIN:
51                  String asciiHost = IDN.toASCII(host);
52                  if (asciiHost.length() > 255) {
53                      throw new IllegalArgumentException(host + " IDN: " + asciiHost + " exceeds 255 char limit");
54                  }
55                  host = asciiHost;
56                  break;
57              case IPv6:
58                  if (!NetUtil.isValidIpV6Address(host)) {
59                      throw new IllegalArgumentException(host + " is not a valid IPv6 address");
60                  }
61                  break;
62              case UNKNOWN:
63                  break;
64          }
65          if (port <= 0 || port >= 65536) {
66              throw new IllegalArgumentException(port + " is not in bounds 0 < x < 65536");
67          }
68          this.cmdType = cmdType;
69          this.addressType = addressType;
70          this.host = host;
71          this.port = port;
72      }
73  
74      /**
75       * Returns the {@link SocksCmdType} of this {@link SocksCmdRequest}
76       *
77       * @return The {@link SocksCmdType} of this {@link SocksCmdRequest}
78       */
79      public SocksCmdType cmdType() {
80          return cmdType;
81      }
82  
83      /**
84       * Returns the {@link SocksAddressType} of this {@link SocksCmdRequest}
85       *
86       * @return The {@link SocksAddressType} of this {@link SocksCmdRequest}
87       */
88      public SocksAddressType addressType() {
89          return addressType;
90      }
91  
92      /**
93       * Returns host that is used as a parameter in {@link SocksCmdType}
94       *
95       * @return host that is used as a parameter in {@link SocksCmdType}
96       */
97      public String host() {
98          return addressType == SocksAddressType.DOMAIN ? IDN.toUnicode(host) : host;
99      }
100 
101     /**
102      * Returns port that is used as a parameter in {@link SocksCmdType}
103      *
104      * @return port that is used as a parameter in {@link SocksCmdType}
105      */
106     public int port() {
107         return port;
108     }
109 
110     @Override
111     public void encodeAsByteBuf(ByteBuf byteBuf) {
112         byteBuf.writeByte(protocolVersion().byteValue());
113         byteBuf.writeByte(cmdType.byteValue());
114         byteBuf.writeByte(0x00);
115         byteBuf.writeByte(addressType.byteValue());
116         switch (addressType) {
117             case IPv4: {
118                 byteBuf.writeBytes(NetUtil.createByteArrayFromIpAddressString(host));
119                 ByteBufUtil.writeShortBE(byteBuf, port);
120                 break;
121             }
122 
123             case DOMAIN: {
124                 byteBuf.writeByte(host.length());
125                 byteBuf.writeCharSequence(host, CharsetUtil.US_ASCII);
126                 ByteBufUtil.writeShortBE(byteBuf, port);
127                 break;
128             }
129 
130             case IPv6: {
131                 byteBuf.writeBytes(NetUtil.createByteArrayFromIpAddressString(host));
132                 ByteBufUtil.writeShortBE(byteBuf, port);
133                 break;
134             }
135         }
136     }
137 }