/* * This file is part of the OWASP Proxy, a free intercepting proxy library. * Copyright (C) 2008-2010 Rogan Dawes <rogan@dawes.za.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to: * The Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ package org.owasp.proxy.socks.impl; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import org.owasp.proxy.util.AsciiString; /** * SOCKS4 Reply/Request message. */ public class Socks4Message extends ProxyMessage { private byte[] msgBytes; private int msgLength; /** * Server failed reply, cmd command for failed request */ public Socks4Message(int cmd) { super(cmd, null, 0); this.user = null; msgLength = 2; msgBytes = new byte[2]; msgBytes[0] = (byte) 0; msgBytes[1] = (byte) command; } /** * Server successfull reply */ public Socks4Message(int cmd, InetAddress ip, int port) { this(0, cmd, ip, port, null); } /** * Client request */ public Socks4Message(int cmd, InetAddress ip, int port, String user) { this(SOCKS_VERSION, cmd, ip, port, user); } /** * Most general constructor */ public Socks4Message(int version, int cmd, InetAddress ip, int port, String user) { super(cmd, ip, port); this.user = user; this.version = version; msgLength = user == null ? 8 : 9 + user.length(); msgBytes = new byte[msgLength]; msgBytes[0] = (byte) version; msgBytes[1] = (byte) command; msgBytes[2] = (byte) (port >> 8); msgBytes[3] = (byte) port; byte[] addr; if (ip != null) addr = ip.getAddress(); else { addr = new byte[4]; addr[0] = addr[1] = addr[2] = addr[3] = 0; } System.arraycopy(addr, 0, msgBytes, 4, 4); if (user != null) { byte[] buf = user.getBytes(); System.arraycopy(buf, 0, msgBytes, 8, buf.length); msgBytes[msgBytes.length - 1] = 0; } } /** * Initialise from the stream If clientMode is true attempts to read a server response otherwise reads a client * request see read for more detail */ public Socks4Message(InputStream in, boolean clientMode) throws IOException { msgBytes = null; read(in, clientMode); } public void read(InputStream in) throws IOException { read(in, true); } public void read(InputStream in, boolean clientMode) throws IOException { DataInputStream d_in = new DataInputStream(in); version = d_in.readUnsignedByte(); command = d_in.readUnsignedByte(); if (clientMode && command != REPLY_OK) { String errMsg; if (command > REPLY_OK && command < REPLY_BAD_IDENTD) errMsg = replyMessage[command - REPLY_OK]; else errMsg = "Unknown Reply Code"; throw new SocksException(command, errMsg); } port = d_in.readUnsignedShort(); byte[] addr = new byte[4]; d_in.readFully(addr); if (addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] != 0 && !clientMode) { user = AsciiString.create(readVariableLengthField(in)); host = AsciiString.create(readVariableLengthField(in)); ip = InetAddress.getByName(host); } else { ip = InetAddress.getByAddress(addr); host = ip.getHostName(); if (!clientMode) { user = AsciiString.create(readVariableLengthField(in)); } } } private byte[] readVariableLengthField(InputStream in) throws IOException { int b; final ByteArrayOutputStream bos = new ByteArrayOutputStream(); while ((b = in.read()) != -1) { if (b == 0) { break; } else { bos.write(b); } } return bos.toByteArray(); } public void write(OutputStream out) throws IOException { if (msgBytes == null) { Socks4Message msg = new Socks4Message(version, command, ip, port, user); msgBytes = msg.msgBytes; msgLength = msg.msgLength; } out.write(msgBytes); } // Constants static final String[] replyMessage = { "Request Granted", "Request Rejected or Failed", "Failed request, can't connect to Identd", "Failed request, bad user name" }; static final int SOCKS_VERSION = 4; public final static int REQUEST_CONNECT = 1; public final static int REQUEST_BIND = 2; public final static int REPLY_OK = 90; public final static int REPLY_REJECTED = 91; public final static int REPLY_NO_CONNECT = 92; public final static int REPLY_BAD_IDENTD = 93; }