package net.sourceforge.jsocks; import java.awt.Button; import java.awt.Component; import java.awt.Container; import java.awt.Font; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Label; import java.awt.SystemColor; import java.awt.TextArea; import java.awt.TextField; 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.DatagramPacket; import java.net.ServerSocket; import java.net.Socket; import java.net.URL; import java.net.UnknownHostException; import net.sourceforge.jsocks.socks.Proxy; import net.sourceforge.jsocks.socks.Socks5DatagramSocket; import net.sourceforge.jsocks.socks.Socks5Proxy; import net.sourceforge.jsocks.socks.SocksDialog; import net.sourceforge.jsocks.socks.SocksServerSocket; import net.sourceforge.jsocks.socks.SocksSocket; public class SocksEcho extends Frame implements ActionListener, Runnable, WindowListener{ //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 Proxy 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); socks_dialog.useThreads = false; URL icon_url = SocksEcho.class.getResource("SocksEcho.gif"); if(icon_url != null){ try{ Object content = icon_url.getContent(); if(content instanceof java.awt.image.ImageProducer) setIconImage(createImage((java.awt.image.ImageProducer) content)); }catch(IOException ioe){ } } addWindowListener(this); 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 /////////////////////////// @Override public void actionPerformed(ActionEvent ae){ 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 /////////////////////////////// @Override 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(UnknownHostException uh_ex){ if(mode != ABORT_MODE){ finished_OK = false; status("Host "+host+" has no DNS entry."); uh_ex.printStackTrace(); } }catch(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("Disconnecting..."); 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(){ 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(){ Proxy 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(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(IOException 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(); 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{ 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{ byte[] data = message.getBytes(); DatagramPacket dp = new DatagramPacket(data,data.length,null,port); udp_sock.send(dp,host); }catch(UnknownHostException uhe){ status("Host "+host+" has no DNS entry."); }catch(IOException ioe){ status("IOException:"+ioe); abort_connection(); } } private void send(String s){ try{ out.write(s.getBytes()); }catch(IOException io_ex){ println("IOException:"+io_ex); abort_connection(); } } /*====================================================================== Form: Table: +---+---------------+ | | | +---+---+---+---+---+ | | | | | | +---+---+---+---+---+ | | +-------------------+ | | +---+---+---+---+---+ | | | | | | +---+---+---+---+---+ | | +-------------------+ */ void guiInit(){ //Some default names used Label label; Container container; 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 ///////////////////////////////// @Override public void windowActivated(java.awt.event.WindowEvent e){ } @Override public void windowDeactivated(java.awt.event.WindowEvent e){ } @Override public void windowOpened(java.awt.event.WindowEvent e){ } @Override public void windowClosing(java.awt.event.WindowEvent e){ if(e.getWindow() == this) onQuit(); else e.getWindow().dispose(); } @Override public void windowClosed(java.awt.event.WindowEvent e){ } @Override public void windowIconified(java.awt.event.WindowEvent e){ } @Override public void windowDeiconified(java.awt.event.WindowEvent e){ } // Main //////////////////////////////////// public static void main(String[] args){ SocksEcho socksecho = new SocksEcho(); socksecho.pack(); socksecho.show(); } }//end class