Link to home
Start Free TrialLog in
Avatar of jasonslogan
jasonslogan

asked on

JAVA - Port Forwarding Program

I have COMPUTER A, B, C

Computer A connects to B while B is listening on port 1234 let's say.  Then B connects to C on port 23 for example.

I need to write a java program that will allow A and B to talk to B and C.  A port forwarding program.  Can someone show me examples because I'm having trouble with mine where the data only moves when I press keys on the keyboard.
Avatar of Mayank S
Mayank S
Flag of India image

Application B in this needs to act like a middleman or a hub in between A and C. You could look at designing it this way:

https://www.experts-exchange.com/questions/21757720/Is-there-any-sample-online-for-socket-and-multi-thread.html#16084277

>> Can someone show me examples because I'm having trouble with mine where the data only moves when I press keys on the keyboard.

What problems?
I don't know why you forward the data in this way but I feel this is a good candidate for the pub/sub architecture than the P2P. Think of the JMS or Tibco Rendezvous.

Where in all the system( which interested in the data from publisher ) subscribe to a publisher( the one recieve data from external source ). Whenever the pub receives the data, it notifies the subs and then the subs make call to the pub to get the data!
Avatar of ADSLMark
ADSLMark

Ok, ive created a very simple example to show you how it can be done. It works, but error-handling etc is very bad. It's just a small *working* sketch. It does not close connections correctly, but you can build from this.
Three files:
Forwarder.java // this class connects a input port to an output port
Pipe.java // this class connects the input and output streams
Example.java // just a small example showing that it works, receives input from standard in, writes it to socket. It does not pipe the responses (one way port forwarding)

//Forwarder.java//
package pf;

import java.io.*;
import java.net.*;

class Forwarder
    extends Thread
{
    private ServerSocket in;
    private PrintWriter out;

    private int in_port;
    private int out_port;

    public Forwarder(int in_port)
        throws IOException
    {
        this.in_port = in_port;
        this.out_port = 0;
        this.in = new ServerSocket(in_port);
        this.out = new PrintWriter(System.out);
    }

    public Forwarder(int in_port, String out_host, int out_port)
        throws IOException
    {
        this.in_port = in_port;
        this.out_port = out_port;
        this.in = new ServerSocket(in_port);
        this.out = new PrintWriter(new Socket(out_host, out_port).getOutputStream(),true);
    }

    public void run()
    {
        try
        {
            System.out.println("Accepting connections on port "+in_port+" streaming to "+out_port);

            while(true)
            {
                Socket s = this.in.accept();
                BufferedReader s_in = new BufferedReader(new InputStreamReader(s.getInputStream()));
                Pipe p = new Pipe(s_in, this.out);
                p.start();
            }
        }
        catch(IOException ioe)
        {
            System.err.println("I/O exception");
        }
    }

    public static void main(String[] args)
        throws IOException
    {
        if(args.length == 3)
        {
            Forwarder fw = new Forwarder(Integer.parseInt(args[0])
                                        ,args[1]
                                        ,Integer.parseInt(args[2]));
            fw.start();
        }
        else if(args.length == 1)
        {
            Forwarder fw = new Forwarder(Integer.parseInt(args[0]));
            fw.start();
        }
        else
        {
            System.out.println("Usage: java pf.Forwarder <in port> [<host> <out port>]");
            return;
        }


    }
}
//--------------------//
//Pipe.java//
package pf;

import java.io.*;
import java.net.*;

class Pipe
    extends Thread
{
    private BufferedReader in;
    private PrintWriter out;

    public Pipe(BufferedReader in, PrintWriter out)
    {
        this.in = in;
        this.out = out;
    }

    public void run()
    {
        try
        {
            String line;
            while((line=in.readLine())!=null)
            {
                System.out.println(line);
                this.out.println(line);
            }
        }
        catch(IOException ioe)
        {
            System.err.println("I/O exception");
        }
    }
}
//--------------------//
//Example.java//
package pf;

import java.io.*;
import java.net.*;

public class Example
    extends Thread
{
    private Socket server;
    private BufferedReader in;
    private PrintWriter out;

    public Example(String host, int port)
        throws IOException
    {
        this.server = new Socket(host, port);
        this.in = new BufferedReader(new InputStreamReader(this.server.getInputStream()));
        this.out = new PrintWriter(this.server.getOutputStream(), true);
    }

    public void run()
    {
        try
        {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String line;
            while((line=br.readLine())!=null)
                this.out.println(line);
        }
        catch(IOException ioe)
        {
            System.err.println("I/O exception");
        }
    }

    public static void main(String[] args)
        throws IOException
    {
        if(args.length == 2)
        {
            Example ex = new Example(args[0], Integer.parseInt(args[1]));
            ex.start();
        }
        else
        {
            System.out.println("Usage: java pf.Example <host> <out port>");
            return;
        }
    }
}
//--------------------//

This is how you run the example:
put everything in the same directory
compile with:
    javac *.java -d .
run first the 'terminal' node
    java portforwarder.Forwarder 9999
run a 'portforwarder' node
    java portforwarder.Forwarder 8888 localhost 9999
optional run another 'portforwarder' node
    java portforwarder.Forwarder 1234 localhost 8888
etc.
run the user interface:
   java portforwarder.Example localhost 1234

Enjoy!
Mark
Avatar of jasonslogan

ASKER

Thank you all and especially Mark for providing an example.

Mark, is there a way to make this pass binary data instead of simply text?  AND THANK YOU for your quick response...

Jason
Sure, just change all the streams into their corresponding byte streams...

Mark
I haven't done this in Java before...  What do I wrap the socket with like PrintWriter that will output byte streams?
ASKER CERTIFIED SOLUTION
Avatar of ADSLMark
ADSLMark

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Note that i convert the string into a byte array. You could also imagine the user giving a command like:

file <filename>

and that you then read this file and stream this to the socket. So although the example is basically the same, internally you can do more (ie. send byte arrays).

I hope this puts you in the right direction.
Mark
I was able to run it but it won't work for non text input.  My goal is to open a port on a server in a DMZ (1234 for example) then forward that to another computer behind the firewall say srv-trm:23

This way I can telnet to my server from the internet on port 1234 and it will give me the termserv server on it's port 23.

Your solution definitely works so I can make another question for this and give you additional points if you think that would be more fair.

Let me know what you would like.  I don't mind learning new things but I've never messed with streams over the internet much.  And the ones I did I used printwriter which converts everything to strings and I need pure byte data because there are a lot of characters that are sent in this emulation of my termserv server.
In your example I had to press enter for it to send.  I need something that will send anything to and from not depending on anything.  If something shows up in the read buffer send it along and so forth.
ah :-) that's another problem.
Read this:
http://forum.java.sun.com/thread.jspa?threadID=677391&messageID=3953865

You can change the way input is send to the socket you connect to, but in my understanding its not possible to easily flush the input buffer with a console. If you had a gui around, then you can catch keyevents and whenever a key is pressed, just flush the buffer.
Anyway, the solution to send data through the pipeline is to call flush(). It completely depends on how and when you want to send data through this pipeline (does it really need to be after every byte? do you want to send commands? send binary files?).

If you really think you need a console application and want to process every keypress by flushing it through the pipeline, then you have to look at JNI to get it done. I think there are libraries out there which will do the job, but I truly doubt you really need them (if you did, you would probably know ;-) .. )

Mark
This is going to be used to forward all kinds of stuff.  Telnet apps, remote desktop on port 3389 and so forth.  My server would be listening on port 4000 then connects to a computer on the lan side on port 3389 to get remote desktop of a computer behind the firewall.  This is a way to get to your computer at work without installing any additional software on the workstations.

So as you see, I need something that will transmit data when there IS data to transmit in both directions.  Can that be done with Java?
Not sure if this will help but...

Have two things happening at the same time.  Have computer A transmitting data to C and C to A.  The data send by computer A could be anything I choose.  It could be listening on port 5000 and be talking to a computer internally on port 80 for a webserver.  I then browse with my browser http://whatever.com:5000 and it will connect to the internal server's web server and act as if all was normal.

I have a C program that does this but it is terrible.  It has not gui and it stops working and I have to start it over again and again.

Sorry I wasn't clear enough initially about my usage of this program.  I assumed if something could pass data period it could pass it the way I needed it.  Not just textual data like a chat program.
Ok, so what I don't understand is why this solution doesn't work for you..
I agree, it only forwards and doesn't 'backwards' stuff, but I can fix that..
So, basically what I've written for you is this:
A class "Forwarder" and "Pipe" which setup a program which listens on some port X and outputs everything directly to some output port Y.
The example class is just an example, to show that it works. You can also run the Forwarder with some real applications and it will just forward those things.

For example, it should work if you setup your system like:
pc A runs a browser which connects to some server on port 5000.
pc B runs a Forwarder listening on port 5000 and forwards all data to port 80 on some pc C.
pc C receives the input from pc B.

Now, I will try to make the Forwarder bi-directional, sending data forward/backwards data. This solves your problem, no? You can replace the example class to anything you like......

Mark