package com.runjva.sourceforge.jsocks.main; import com.runjva.sourceforge.jsocks.protocol.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowListener; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.*; public class SocksEcho extends Frame implements ActionListener, Runnable, WindowListener { Logger log = LoggerFactory.getLogger(SocksEcho.class); /** * */ private static final long serialVersionUID = 1L; // GUI components TextField host_text, port_text, input_text; Button proxy_button, accept_button, clear_button, connect_button, udp_button, quit_button; TextArea output_textarea; Label status_label; SocksDialog socks_dialog; // Network related members SocksProxyBase proxy = null; int port; String host; Thread net_thread = null; InputStream in = null; OutputStream out = null; Socket sock = null; ServerSocket server_sock = null; Socks5DatagramSocket udp_sock; Object net_lock = new Object(); int mode = COMMAND_MODE; // Possible mode states. static final int LISTEN_MODE = 0; static final int CONNECT_MODE = 1; static final int UDP_MODE = 2; static final int COMMAND_MODE = 3; static final int ABORT_MODE = 4; // Maximum datagram size static final int MAX_DATAGRAM_SIZE = 1024; // Constructors // ////////////////////////////////// public SocksEcho() { super("SocksEcho"); guiInit(); socks_dialog = new SocksDialog(this); SocksDialog.useThreads = false; final URL icon_url = SocksEcho.class.getResource("SocksEcho.gif"); if (icon_url != null) { try { final Object content = icon_url.getContent(); if (content instanceof java.awt.image.ImageProducer) { setIconImage(createImage((java.awt.image.ImageProducer) content)); } } catch (final IOException ioe) { log.debug("Could not getContent() for {}", icon_url, ioe); } } addWindowListener(this); final Component component[] = getComponents(); for (int i = 0; i < component.length; ++i) { if (component[i] instanceof Button) { ((Button) component[i]).addActionListener(this); } else if (component[i] instanceof TextField) { ((TextField) component[i]).addActionListener(this); } } } // ActionListener interface // ///////////////////////// public void actionPerformed(ActionEvent ae) { final Object source = ae.getSource(); if (source == proxy_button) { onProxy(); } else if (source == quit_button) { onQuit(); } else if ((source == connect_button) || (source == port_text) || (source == host_text)) { onConnect(); } else if (source == input_text) { onInput(); } else if (source == accept_button) { onAccept(); } else if (source == udp_button) { onUDP(); } else if (source == clear_button) { onClear(); } } // Runnable interface // ///////////////////////////// public void run() { boolean finished_OK = true; try { switch (mode) { case UDP_MODE: startUDP(); doUDPPipe(); break; case LISTEN_MODE: doAccept(); doPipe(); break; case CONNECT_MODE: doConnect(); doPipe(); break; default: warn("Unexpected mode in run() method"); } } catch (final UnknownHostException uh_ex) { if (mode != ABORT_MODE) { finished_OK = false; status("Host " + host + " has no DNS entry."); uh_ex.printStackTrace(); } } catch (final IOException io_ex) { if (mode != ABORT_MODE) { finished_OK = false; status("" + io_ex); io_ex.printStackTrace(); } } finally { if (mode == ABORT_MODE) { status("Connection closed"); } else if (finished_OK) { status("Connection closed by foreign host."); } onDisconnect(); } } // Private methods // ////////////////////////////////////////////////////////////////////// // GUI event handlers. // //////////////////////// private void onConnect() { if (mode == CONNECT_MODE) { status("Diconnecting..."); abort_connection(); return; } else if (mode != COMMAND_MODE) { return; } if (!readHost()) { return; } if (!readPort()) { return; } if (proxy == null) { warn("Proxy is not set"); onProxy(); return; } startNetThread(CONNECT_MODE); status("Connecting to " + host + ":" + port + " ..."); connect_button.setLabel("Disconnect"); connect_button.invalidate(); accept_button.setEnabled(false); udp_button.setEnabled(false); doLayout(); input_text.requestFocus(); } private void onDisconnect() { synchronized (net_lock) { mode = COMMAND_MODE; connect_button.setLabel("Connect"); accept_button.setLabel("Accept"); udp_button.setLabel("UDP"); accept_button.setEnabled(true); connect_button.setEnabled(true); udp_button.setEnabled(true); server_sock = null; sock = null; out = null; in = null; net_thread = null; } } private void onAccept() { if (mode == LISTEN_MODE) { abort_connection(); return; } else if (mode != COMMAND_MODE) { return; } if (!readHost()) { return; } if (!readPort()) { port = 0; } if (proxy == null) { warn("Proxy is not set"); onProxy(); return; } startNetThread(LISTEN_MODE); accept_button.setLabel("Abort"); connect_button.setEnabled(false); udp_button.setEnabled(false); input_text.requestFocus(); } private void onUDP() { if (mode == UDP_MODE) { abort_connection(); return; } else if (mode == ABORT_MODE) { return; } if (proxy == null) { warn("Proxy is not set"); onProxy(); return; } startNetThread(UDP_MODE); udp_button.setLabel("Abort"); connect_button.setEnabled(false); accept_button.setEnabled(false); udp_button.invalidate(); doLayout(); input_text.requestFocus(); } private void onInput() { final String send_string = input_text.getText() + "\n"; switch (mode) { case ABORT_MODE: // Fall through case COMMAND_MODE: return; case CONNECT_MODE:// Fall through case LISTEN_MODE: synchronized (net_lock) { if (out == null) { return; } send(send_string); } break; case UDP_MODE: if (!readHost()) { return; } if (!readPort()) { return; } sendUDP(send_string, host, port); break; default: print("Unknown mode in onInput():" + mode); } input_text.setText(""); print(send_string); } private void onClear() { output_textarea.setText(""); } private void onProxy() { SocksProxyBase p; p = socks_dialog.getProxy(proxy); if (p != null) { proxy = p; } if ((proxy != null) && (proxy instanceof Socks5Proxy)) { ((Socks5Proxy) proxy).resolveAddrLocally(false); } } private void onQuit() { dispose(); System.exit(0); } // Data retrieval functions // //////////////////////// /** * Reads the port field, returns false if parsing fails. */ private boolean readPort() { try { port = Integer.parseInt(port_text.getText()); } catch (final NumberFormatException nfe) { warn("Port invalid!"); return false; } return true; } private boolean readHost() { host = host_text.getText(); host.trim(); if (host.length() < 1) { warn("Host is not set"); return false; } return true; } // Display functions // ///////////////// private void status(String s) { status_label.setText(s); } private void println(String s) { output_textarea.append(s + "\n"); } private void print(String s) { output_textarea.append(s); } private void warn(String s) { status(s); // System.err.println(s); } // Network related functions // ////////////////////////// private void startNetThread(int m) { mode = m; net_thread = new Thread(this); net_thread.start(); } private void abort_connection() { synchronized (net_lock) { if (mode == COMMAND_MODE) { return; } mode = ABORT_MODE; if (net_thread != null) { try { if (sock != null) { sock.close(); } if (server_sock != null) { server_sock.close(); } if (udp_sock != null) { udp_sock.close(); } } catch (final IOException ioe) { log.warn("abort_connection(): could not close socket", ioe); } net_thread.interrupt(); net_thread = null; } } } private void doAccept() throws IOException { println("Trying to accept from " + host); status("Trying to accept from " + host); println("Using proxy:" + proxy); server_sock = new SocksServerSocket(proxy, host, port); // server_sock.setSoTimeout(30000); println("Listenning on: " + server_sock.getInetAddress() + ":" + server_sock.getLocalPort()); sock = server_sock.accept(); println("Accepted from:" + sock.getInetAddress() + ":" + sock.getPort()); status("Accepted from:" + sock.getInetAddress().getHostAddress() + ":" + sock.getPort()); server_sock.close(); // Even though this doesn't do anything } private void doConnect() throws IOException { println("Trying to connect to:" + host + ":" + port); println("Using proxy:" + proxy); sock = new SocksSocket(proxy, host, port); println("Connected to:" + sock.getInetAddress() + ":" + port); status("Connected to: " + sock.getInetAddress().getHostAddress() + ":" + port); println("Via-Proxy:" + sock.getLocalAddress() + ":" + sock.getLocalPort()); } private void doPipe() throws IOException { out = sock.getOutputStream(); in = sock.getInputStream(); final byte[] buf = new byte[1024]; int bytes_read; while ((bytes_read = in.read(buf)) > 0) { print(new String(buf, 0, bytes_read)); } } private void startUDP() throws IOException { udp_sock = new Socks5DatagramSocket(proxy, 0, null); println("UDP started on " + udp_sock.getLocalAddress() + ":" + udp_sock.getLocalPort()); status("UDP:" + udp_sock.getLocalAddress().getHostAddress() + ":" + udp_sock.getLocalPort()); } private void doUDPPipe() throws IOException { final DatagramPacket dp = new DatagramPacket( new byte[MAX_DATAGRAM_SIZE], MAX_DATAGRAM_SIZE); while (true) { udp_sock.receive(dp); print("UDP\n" + "From:" + dp.getAddress() + ":" + dp.getPort() + "\n" + "\n" + // Java 1.2 // new // String(dp.getData(),dp.getOffset(),dp.getLength())+"\n" // Java 1.1 new String(dp.getData(), 0, dp.getLength()) + "\n"); dp.setLength(MAX_DATAGRAM_SIZE); } } private void sendUDP(String message, String host, int port) { if (!udp_sock.isProxyAlive(100)) { status("Proxy closed connection"); abort_connection(); return; } try { final byte[] data = message.getBytes(); final DatagramPacket dp = new DatagramPacket(data, data.length, null, port); udp_sock.send(dp, host); } catch (final UnknownHostException uhe) { status("Host " + host + " has no DNS entry."); } catch (final IOException ioe) { status("IOException:" + ioe); abort_connection(); } } private void send(String s) { try { out.write(s.getBytes()); } catch (final IOException io_ex) { println("IOException:" + io_ex); abort_connection(); } } /* * ====================================================================== * Form: Table: +---+---------------+ | | | +---+---+---+---+---+ | | | | | * | +---+---+---+---+---+ | | +-------------------+ | | * +---+---+---+---+---+ | | | | | | +---+---+---+---+---+ | | * +-------------------+ */ void guiInit() { // Some default names used Label label; Container container; final GridBagConstraints c = new GridBagConstraints(); container = this; // container = new Panel(); container.setLayout(new GridBagLayout()); container.setBackground(SystemColor.menu); c.insets = new Insets(3, 3, 3, 3); c.gridx = 0; c.gridy = 0; c.gridwidth = 1; c.gridheight = 1; c.anchor = GridBagConstraints.NORTHEAST; label = new Label("Host:"); container.add(label, c); c.gridx = 0; c.gridy = 1; c.gridwidth = 1; c.gridheight = 1; c.anchor = GridBagConstraints.NORTHEAST; label = new Label("Port:"); container.add(label, c); c.gridx = 0; c.gridy = 5; c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = 1; c.fill = GridBagConstraints.HORIZONTAL; c.insets = new Insets(0, 0, 0, 0); status_label = new Label(""); container.add(status_label, c); c.insets = new Insets(3, 3, 3, 3); c.gridx = 1; c.gridy = 0; c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = 1; c.anchor = GridBagConstraints.NORTHWEST; c.fill = GridBagConstraints.HORIZONTAL; host_text = new TextField(""); container.add(host_text, c); c.weightx = 1.0; c.fill = GridBagConstraints.NONE; c.gridx = 1; c.gridy = 1; c.gridwidth = 1; c.gridheight = 1; c.anchor = GridBagConstraints.NORTHWEST; port_text = new TextField("", 5); container.add(port_text, c); c.weightx = 0.0; c.gridx = 0; c.gridy = 3; c.fill = GridBagConstraints.HORIZONTAL; c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = 1; c.anchor = GridBagConstraints.NORTHWEST; input_text = new TextField(""); container.add(input_text, c); c.fill = GridBagConstraints.NONE; c.gridx = 2; c.gridy = 1; c.gridwidth = 1; c.gridheight = 1; c.anchor = GridBagConstraints.NORTHEAST; connect_button = new Button("Connect"); container.add(connect_button, c); c.gridx = 3; c.gridy = 1; c.gridwidth = 1; c.gridheight = 1; c.anchor = GridBagConstraints.EAST; accept_button = new Button("Accept"); container.add(accept_button, c); c.gridx = 4; c.gridy = 1; c.gridwidth = 1; c.gridheight = 1; c.anchor = GridBagConstraints.EAST; udp_button = new Button("UDP"); container.add(udp_button, c); c.gridx = 0; c.gridy = 4; c.gridwidth = 1; c.gridheight = 1; c.anchor = GridBagConstraints.NORTHWEST; proxy_button = new Button("Proxy..."); container.add(proxy_button, c); c.gridx = 3; c.gridy = 4; c.gridwidth = 1; c.gridheight = 1; c.anchor = GridBagConstraints.NORTHEAST; clear_button = new Button("Clear"); container.add(clear_button, c); c.gridx = 4; c.gridy = 4; c.gridwidth = 1; c.gridheight = 1; c.anchor = GridBagConstraints.EAST; quit_button = new Button("Quit"); container.add(quit_button, c); c.weightx = 1.0; c.weighty = 1.0; c.fill = GridBagConstraints.BOTH; c.gridx = 0; c.gridy = 2; c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = 1; c.anchor = GridBagConstraints.NORTHWEST; output_textarea = new TextArea("", 10, 50); output_textarea.setFont(new Font("Monospaced", Font.PLAIN, 11)); output_textarea.setEditable(false); // output_textarea.setEnabled(false); container.add(output_textarea, c); }// end guiInit // WindowListener Interface // /////////////////////////////// public void windowActivated(java.awt.event.WindowEvent e) { } public void windowDeactivated(java.awt.event.WindowEvent e) { } public void windowOpened(java.awt.event.WindowEvent e) { } public void windowClosing(java.awt.event.WindowEvent e) { if (e.getWindow() == this) { onQuit(); } else { e.getWindow().dispose(); } } public void windowClosed(java.awt.event.WindowEvent e) { } public void windowIconified(java.awt.event.WindowEvent e) { } public void windowDeiconified(java.awt.event.WindowEvent e) { } // Main // ////////////////////////////////// public static void main(String[] args) { final SocksEcho socksecho = new SocksEcho(); socksecho.pack(); socksecho.setVisible(true); } }// end class