001 /* 002 * ftp4j - A pure Java FTP client library 003 * 004 * Copyright (C) 2008 Carlo Pelliccia (www.sauronsoftware.it) 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 */ 019 package it.sauronsoftware.ftp4j.connectors; 020 021 import it.sauronsoftware.ftp4j.FTPConnection; 022 import it.sauronsoftware.ftp4j.FTPConnector; 023 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.io.OutputStream; 027 import java.net.InetAddress; 028 import java.net.Socket; 029 030 /** 031 * This one connects a remote ftp host through a SOCKS4/4a proxy server. 032 * 033 * @author Carlo Pelliccia 034 */ 035 public class SOCKS4Connector implements FTPConnector { 036 037 /** 038 * The socks4 proxy host name. 039 */ 040 private String socks4host; 041 042 /** 043 * The socks4 proxy port. 044 */ 045 private int socks4port; 046 047 /** 048 * The socks4 proxy user (optional). 049 */ 050 private String socks4user; 051 052 /** 053 * It builds the connector. 054 * 055 * @param socks4host 056 * The socks4 proxy host name. 057 * @param socks4port 058 * The socks4 proxy port. 059 * @param socks4user 060 * The socks4 proxy user (optional, can be set to null). 061 */ 062 public SOCKS4Connector(String socks4host, int socks4port, String socks4user) { 063 this.socks4host = socks4host; 064 this.socks4port = socks4port; 065 this.socks4user = socks4user; 066 } 067 068 /** 069 * It builds the connector. 070 * 071 * @param socks4host 072 * The socks4 proxy host name. 073 * @param socks4port 074 * The socks4 proxy port. 075 */ 076 public SOCKS4Connector(String socks4host, int socks4port) { 077 this(socks4host, socks4port, null); 078 } 079 080 private FTPConnection connect(String host, int port) throws IOException { 081 // Socks 4 or 4a? 082 boolean socks4a = false; 083 byte[] address; 084 try { 085 address = InetAddress.getByName(host).getAddress(); 086 } catch (Exception e) { 087 // Cannot resolve host, switch to version 4a. 088 socks4a = true; 089 address = new byte[] { 0x00, 0x00, 0x00, 0x01 }; 090 } 091 // A connection status flag. 092 boolean connected = false; 093 // The socket for the connection with the proxy. 094 Socket socket = null; 095 InputStream in = null; 096 OutputStream out = null; 097 // FTPConnection routine. 098 try { 099 socket = new Socket(socks4host, socks4port); 100 in = socket.getInputStream(); 101 out = socket.getOutputStream(); 102 // Send the request. 103 // Version 4. 104 out.write(0x04); 105 // CONNECT method. 106 out.write(0x01); 107 // Remote port number. 108 out.write(port >> 8); 109 out.write(port); 110 // Remote host address. 111 out.write(address); 112 // The user. 113 if (socks4user != null) { 114 out.write(socks4user.getBytes("UTF-8")); 115 } 116 // End of user. 117 out.write(0x00); 118 // Version 4a? 119 if (socks4a) { 120 out.write(host.getBytes("UTF-8")); 121 out.write(0x00); 122 } 123 // Get and parse the response. 124 int aux = read(in); 125 if (aux != 0x00) { 126 throw new IOException("SOCKS4Connector: invalid proxy response"); 127 } 128 aux = read(in); 129 switch (aux) { 130 case 0x5a: 131 in.skip(6); 132 connected = true; 133 break; 134 case 0x5b: 135 throw new IOException( 136 "SOCKS4Connector: connection refused/failed"); 137 case 0x5c: 138 throw new IOException( 139 "SOCKS4Connector: cannot validate the user"); 140 case 0x5d: 141 throw new IOException("SOCKS4Connector: invalid user"); 142 default: 143 throw new IOException("SOCKS4Connector: invalid proxy response"); 144 } 145 } catch (IOException e) { 146 throw e; 147 } finally { 148 if (!connected) { 149 if (out != null) { 150 try { 151 out.close(); 152 } catch (Throwable t) { 153 ; 154 } 155 } 156 if (in != null) { 157 try { 158 in.close(); 159 } catch (Throwable t) { 160 ; 161 } 162 } 163 if (socket != null) { 164 try { 165 socket.close(); 166 } catch (Throwable t) { 167 ; 168 } 169 } 170 } 171 } 172 return new SocketConnection(socket, in, out); 173 } 174 175 private int read(InputStream in) throws IOException { 176 int aux = in.read(); 177 if (aux < 0) { 178 throw new IOException( 179 "SOCKS4Connector: connection closed by the proxy"); 180 } 181 return aux; 182 } 183 184 public FTPConnection connectForCommunicationChannel(String host, int port) 185 throws IOException { 186 return connect(host, port); 187 } 188 189 public FTPConnection connectForDataTransferChannel(String host, int port) 190 throws IOException { 191 return connect(host, port); 192 } 193 194 }