// Copyright 2000-2005 the Contributors, as shown in the revision logs. // Licensed under the Apache Public Source License 2.0 ("the License"). // You may not use this file except in compliance with the License. package org.ibex.net; import java.net.*; import java.io.*; import org.ibex.io.*; import org.ibex.util.*; import javax.net.ssl.*; // FEATURE: SASL // FEATURE: Torification /** a stream backed by a socket */ public class Connection extends Stream { protected final Socket s; public final String vhost; public Connection(Socket s, String vhost) { super(s); this.vhost = vhost; this.s = s; } protected Connection(InputStream i, OutputStream o) { super(i, o); vhost = null; s = null; } public Socket getSocket() { return s; } public int getLocalPort() { return s.getLocalPort(); } public InetAddress getLocalAddress() { return ((InetSocketAddress)s.getLocalSocketAddress()).getAddress(); } public int getRemotePort() { return s.getPort(); } public InetAddress getRemoteAddress() { return ((InetSocketAddress)s.getRemoteSocketAddress()).getAddress(); } public String getRemoteHostname() { return getRemoteAddress().getHostName(); } public String getVirtualHost() { return vhost; } public void setTimeout(int ms) { try { s.setSoTimeout(ms); } catch(IOException e) { ioe(e); } } public void setTcpNoDelay(boolean delay) { try { s.setTcpNoDelay(delay); } catch(IOException e) { ioe(e); } } /** never throws an exception */ public void close() { try{if (s!=null) s.close();}catch(Exception e){/*ignore*/} super.close(); } public Connection negotiateSSL(boolean server) { try { SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket ssl = (SSLSocket) sslsocketfactory.createSocket(s, vhost, s.getLocalPort(), true); ssl.setUseClientMode(!server); return new Connection(ssl, vhost); } catch (IOException e) { ioe(e); } return null; } static int ioe(IOException e) { if (e instanceof SocketException && e.toString().indexOf("Connection reset")!=-1) throw new Closed(e.getMessage()); throw new StreamException(e); } // FEATURE: SOCKSv5 // FEATURE: SSL // FEATURE: password authentication (inside SSL) /** * Implements SOCKSv4 with v4a DNS extension * @see http://www.socks.nec.com/protocol/socks4.protocol * @see http://www.socks.nec.com/protocol/socks4a.protocol */ public static class SOCKS extends Connection { public SOCKS(String proxyHost, int proxyPort, String host, int port, boolean ssl) throws IOException { super(new SSL(proxyHost, proxyPort, ssl), host); //((SSL)s).negotiateSSL(); try { DataOutputStream dos = new DataOutputStream(s.getOutputStream()); dos.writeByte(0x04); // SOCKSv4(a) dos.writeByte(0x01); // CONNECT dos.writeShort(port & 0xffff); // port //if (addr == null) { dos.writeInt(0x00000001); // bogus IP //} else dos.write(addr.getAddress()); // actual IP dos.writeByte(0x00); // no userid //if (addr == null) { PrintWriter pw = new PrintWriter(new OutputStreamWriter(dos)); pw.print(host); pw.flush(); dos.writeByte(0x00); // hostname null terminator //} dos.flush(); DataInputStream dis = new DataInputStream(s.getInputStream()); dis.readByte(); // reply version byte success = dis.readByte(); // success/fail dis.skip(6); // ip/port if ((int)(success & 0xff) != 90) throw new StreamException("SOCKS error code "+(success & 0xff)); } catch (IOException e) { ioe(e); } } } }