Home | History | Annotate | Download | only in net
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.net;
     19 
     20 import java.nio.ByteOrder;
     21 import java.nio.charset.StandardCharsets;
     22 import libcore.io.Memory;
     23 
     24 class Socks4Message {
     25     static final int COMMAND_CONNECT = 1;
     26 
     27     static final int COMMAND_BIND = 2;
     28 
     29     static final int RETURN_SUCCESS = 90;
     30 
     31     static final int RETURN_FAILURE = 91;
     32 
     33     static final int RETURN_CANNOT_CONNECT_TO_IDENTD = 92;
     34 
     35     static final int RETURN_DIFFERENT_USER_IDS = 93;
     36 
     37     static final int REPLY_LENGTH = 8;
     38 
     39     static final int INDEX_VERSION = 0;
     40 
     41     private static final int SOCKS_VERSION = 4;
     42 
     43     private static final int INDEX_COMMAND = 1;
     44 
     45     private static final int INDEX_PORT = 2;
     46 
     47     private static final int INDEX_IP = 4;
     48 
     49     private static final int INDEX_USER_ID = 8;
     50 
     51     private static final int BUFFER_LENGTH = 256;
     52 
     53     private static final int MAX_USER_ID_LENGTH = BUFFER_LENGTH - INDEX_USER_ID;
     54 
     55     protected byte[] buffer;
     56 
     57     public Socks4Message() {
     58         buffer = new byte[BUFFER_LENGTH];
     59         setVersionNumber(SOCKS_VERSION);
     60     }
     61 
     62     /**
     63      * Get the request's command or result.
     64      */
     65     public int getCommandOrResult() {
     66         return buffer[INDEX_COMMAND];
     67     }
     68 
     69     /**
     70      * Set the request's command or result.
     71      */
     72     public void setCommandOrResult(int command) {
     73         buffer[INDEX_COMMAND] = (byte) command;
     74     }
     75 
     76     /**
     77      * Returns the request's port number.
     78      */
     79     public int getPort() {
     80         return Memory.peekShort(buffer, INDEX_PORT, ByteOrder.BIG_ENDIAN);
     81     }
     82 
     83     /**
     84      * Set the request's port number.
     85      */
     86     public void setPort(int port) {
     87         Memory.pokeShort(buffer, INDEX_PORT, (short) port, ByteOrder.BIG_ENDIAN);
     88     }
     89 
     90     /**
     91      * Returns the IP address of the request as an integer.
     92      */
     93     public int getIP() {
     94         return Memory.peekInt(buffer, INDEX_IP, ByteOrder.BIG_ENDIAN);
     95     }
     96 
     97     /**
     98      * Set the IP address. This expects an array of four bytes in host order.
     99      */
    100     public void setIP(byte[] ip) {
    101         buffer[INDEX_IP] = ip[0];
    102         buffer[INDEX_IP + 1] = ip[1];
    103         buffer[INDEX_IP + 2] = ip[2];
    104         buffer[INDEX_IP + 3] = ip[3];
    105     }
    106 
    107     /**
    108      * Returns the user id for authentication.
    109      */
    110     public String getUserId() {
    111         return getString(INDEX_USER_ID, MAX_USER_ID_LENGTH);
    112     }
    113 
    114     /**
    115      * Set the user id for authentication.
    116      */
    117     public void setUserId(String id) {
    118         setString(INDEX_USER_ID, MAX_USER_ID_LENGTH, id);
    119     }
    120 
    121     @Override
    122     public String toString() {
    123         StringBuilder buf = new StringBuilder(50);
    124         buf.append("Version: ");
    125         buf.append(Integer.toHexString(getVersionNumber()));
    126         buf.append(" Command: ");
    127         buf.append(Integer.toHexString(getCommandOrResult()));
    128         buf.append(" Port: ");
    129         buf.append(getPort());
    130         buf.append(" IP: ");
    131         buf.append(Integer.toHexString(getIP()));
    132         buf.append(" User ID: ");
    133         buf.append(getUserId());
    134         return buf.toString();
    135     }
    136 
    137     /**
    138      * Returns the total number of bytes used for the request. This method
    139      * searches for the end of the user id, then searches for the end of the
    140      * password and returns the final index as the requests length.
    141      */
    142     public int getLength() {
    143         int index = 0;
    144 
    145         // Look for the end of the user id.
    146         for (index = INDEX_USER_ID; buffer[index] != 0; index++) {
    147             /*
    148              * Finds the end of the user id by searching for the null
    149              * termination of the user id string.
    150              */
    151         }
    152 
    153         // Increment the index to include the NULL character in the length;
    154         index++;
    155         return index;
    156     }
    157 
    158     /**
    159      * Returns an error string corresponding to the given error value.
    160      */
    161     public String getErrorString(int error) {
    162         switch (error) {
    163         case RETURN_FAILURE:
    164             return "Failure to connect to SOCKS server";
    165         case RETURN_CANNOT_CONNECT_TO_IDENTD:
    166             return "Unable to connect to identd to verify user";
    167         case RETURN_DIFFERENT_USER_IDS:
    168             return "Failure - user ids do not match";
    169         default:
    170             return "Success";
    171         }
    172     }
    173 
    174     /**
    175      * Returns the message's byte buffer.
    176      */
    177     public byte[] getBytes() {
    178         return buffer;
    179     }
    180 
    181     /**
    182      * Get a String from the buffer at the offset given. The method reads until
    183      * it encounters a null value or reaches the maxLength given.
    184      */
    185     private String getString(int offset, int maxLength) {
    186         int index = offset;
    187         int lastIndex = index + maxLength;
    188         while (index < lastIndex && (buffer[index] != 0)) {
    189             index++;
    190         }
    191         return new String(buffer, offset, index - offset, StandardCharsets.ISO_8859_1);
    192     }
    193 
    194     /**
    195      * Returns the SOCKS version number. Should always be 4.
    196      */
    197     private int getVersionNumber() {
    198         return buffer[INDEX_VERSION];
    199     }
    200 
    201     /**
    202      * Put a string into the buffer at the offset given.
    203      */
    204     private void setString(int offset, int maxLength, String theString) {
    205         byte[] stringBytes = theString.getBytes(StandardCharsets.ISO_8859_1);
    206         int length = Math.min(stringBytes.length, maxLength);
    207         System.arraycopy(stringBytes, 0, buffer, offset, length);
    208         buffer[offset + length] = 0;
    209     }
    210 
    211     /**
    212      * Set the SOCKS version number. This should always be 4.
    213      */
    214     private void setVersionNumber(int number) {
    215         buffer[INDEX_VERSION] = (byte) number;
    216     }
    217 }
    218