8

I need to establish a tcp connection from my house computer to my office computer.

on the office there is a router where several computers are connected to. that router has internet therefore all the computers connected to that router have internet as well. on my house I have a computer with internet access. I need my office computer to act as the server and my home computer to connect to it. Before, I used to be able to connect by port forwarding traffic on the server as:

    NATUPNPLib.UPnPNATClass upnpnat;
    NATUPNPLib.IStaticPortMappingCollection mappings;

    public ServerExample()
    {
        InitializeComponent();

        upnpnat = new NATUPNPLib.UPnPNATClass();
        mappings = upnpnat.StaticPortMappingCollection;

        //                           server local IP address
        mappings.Add(1300, "TCP", 1300, "192.168.150.146", true, "plsease work");
        // this code tels the router to forward all tcp traffic comming from port
        // 1300 to the server computer (it's lan ip address happens to be 192.168.150.146)
        //...

and I was able to connect from my house. (I know that the simple way will be to open the ports on the office router and forward them to my computer the problem is that I do not have access to the office router)

now they replaced the router on my office with a newer one and I am not able to use my code.Now, with the new router, when I execute the privious code I get:

enter image description here

note that mappings returns null; therefore, I am not able to add a mapping.

I am sure there should be a way to establish a connection because some people in the office use limewire for example or bit torrent. I think my problem has to do with permissions maybe? How can I resolve this?


Edit

So from researching I found that what I am trying to do is "UDP punch hole into firewall". I actually want to do it over a tcp connection. I don't know what is will be the difference between tcp and upd puch holing.... I mean the purpose of that is for a client to be able to find a pear without having to do configurations on the router.

.

.

.

.

.

.

UPDATE

OK so I believe I have tried doing what you guys posted on this question with c#: ok let me show you what I did:

note you may need to refer to this diagram in order to understand what I will be explain: enter image description here

As you know I want to establish a tcp connection between computer A and computer B. The way I manage to do this is by doing what is called tcp punch holing.

Step 1: The first thing that I do is to start listening for new connections on the server S.

                   TcpListener server = new TcpListener(System.Net.IPAddress.Parse(“192.168.11.109”), 55550);
                   Server.Start();

                   var client = server.AcceptSocket();  \\ wait here until someone connects

Step 2: Now connect to the server with computer A as:

          TcpClient tcpClient = new TcpClient("192.168.11.109", 55550);

Step 3: After executing step 2 code on computer A the server S debug should look like:

enter image description here

Step 4: Now our goal is to connect from computer B to computer A. Server S has the information that B needs in order to establish the connection. In reality I will have to establish a connection between computer B and server S so that server S can give B the appropriate parameters in order for B to connect to A.

Step 5: since I am debuging I am able to see the parameters so I will make computer A a server now by listening on port 3313. I want computer A to be listening now on that port (3313) because all the packages sent to router X with port 3313 should be sent to computer A.

       \\ COMPUTER A 
       TcpListener server = new TcpListener(System.Net.IPAddress.Parse("192.168.0.120"), 3313);
        server.Start();

        var newClient = server.AcceptSocket();  \\ wait here until a client gets connected

Step 6: So computer A should now be listening for new connections on port 3313. again port 3313 is important because router x should forward all packages received from that port to computer A.

Computer A is waiting for new connections. enter image description here

Step 7: So now quickly! We want to establish that connection from computer B. In reality server S will pass the parameters but since I am just trying to make this work I will write the program really quick on computer B.

          TcpClient tcpClient = new TcpClient(“192.168.11.108”, 3313);
           \\192.168.11.108  is the address of router X

Finally:

For some reason, computer B is not able to connect to computer A.

enter image description here

The reason why it is not able to connect is because router X did not forwarded the packages to computer A. (I know this because I have enabled port forwarding on port 54540 on router X and when I use that port it works) I mean I don’t understand why router X did not forward traffic coming from port 3313 to computer A. Computer A already established a connection to server S and all the things that server S sent to router X through port 3313 got sent to computer A. why is it that if I send packages to router X through port 3313 they don’t get received by computer A!?

PS:

Note that everything that I showed here, I actually have the three routers X, Y and Z and also I have server S, computer A and computer B:

enter image description here

Tono Nam
  • 34,064
  • 78
  • 298
  • 470
  • This is generally not coding issue, but rather administrative/policy: in most organizations exposing internal machines to internet is not allowed. If you are willing to do it anyway I'd recommend directly talking to network administrator in some friendly way.. – Alexei Levenkov Aug 29 '11 at 01:15
  • yeah if I contact administration I should get permission I think. Is just that I am curious because I am able to use bit torrent, lime wire and other p2p applications. and it will be nicer to resolve this with code rather than by talking to administration plus I learn :) – Tono Nam Aug 29 '11 at 03:18
  • those protocole work differently... google for "UDP punch hole into firewall" – Yahia Aug 29 '11 at 04:58
  • http://www.sectechno.com/2010/10/31/bypassing-firewalls-using-icmp-tunnel/ – patrick Sep 02 '11 at 16:54

4 Answers4

4

Your new work router has probably got UPnP disabled, hence your null reference.

Without this your server cannot be made visible to inbound traffic as the router doesn't know where to send the inbound packets. In this case the router acts as a firewall blocking the incoming traffic to your server.

The basic ways around this are:

1) open up UPnP

This enables your application to instruct the router how to forward inbound traffic back to your server.

2) set up a port forwarding

As above by manually configuring the router.

3) make your work server the client

Routers work by allowing outbound connections to initiate the connection. It remembers the return address, rewrites the externally visible IP, and provides an unused port for external traffic to talk back on (NAT). This allows outbound requests to establish communication with the outside and bypass the firewall. If your home IP is fixed you could setup a client at work that tries to call home on a schedule (until you start the server and can establish the connection).

4) use P2P (mediation server)

I'm not sure where you would begin with this, but the principle is this. It usually works on a single UDP port. A server that is not behind NAT is used for establishing connections. The clients send their IP to the server in a UDP packet, and the router rewrites the UDP header with the router return address. The server takes this data and sends it to other peers. With everyone now knowing each others return address, they can send TCP traffic directly to each other and the server steps out of the way.

There's some really good article here regarding the basics of NAT, explained in simple terms. And a good article here which explains how P2P leverages NAT to bypass firewalls.

Hope this gives you some ideas.

TheCodeKing
  • 19,064
  • 3
  • 47
  • 70
  • thanks for the help. it will be nice if you can tel me why I am not still able to do tcp puch holing... take a look at my update on the question. I will really appreciate if you can make this work. – Tono Nam Sep 05 '11 at 19:32
  • I believe you are trying 4) above. This requires the middle server to not be behind a NAT, otherwise the return address is lost as it's rewritten by the router before it hits your server. Ideally you need the router outbound adresses/ports passed on to each machine to connect them together. The return address will be some random port you can't predict, and which only the 2 routers know. – TheCodeKing Sep 05 '11 at 19:52
4

TCP hole punching frequently doesn't work. You're best bet is to stick to UDP hole punching. If you need TCP-like behavior, you can use RDP or a similar protocol that gives you TCP behavior but can use UDP as its transport.

The other approach is to relay all traffic through the server. Each host can connect to the server and the server can copy traffic from one connection to the other.

The best solution would be if you can get some support from the routers such as port forwarding or UPnP.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • I want to avoid relay because then that will consume a lot of cpu usage on the server. But I will look into UPnP some more. Thanks a lot! – Tono Nam Sep 05 '11 at 19:49
  • I doubt it. A '486 can relay 100Mbps. – David Schwartz Sep 05 '11 at 20:50
  • and a relay will be more efficient? transferring of data will be faster? – Tono Nam Sep 05 '11 at 21:20
  • That depends on a lot of factors, including whether you have to fake TCP in user space. – David Schwartz Sep 05 '11 at 22:34
  • I already managed to do udp punch holing. I am transfering files thats why I wanted to use the tcp protocol. Anyways as you said that seems to be very hard to acomplish. I think it should be posible to make sure I dont lose data when using the udp protocol? – Tono Nam Sep 06 '11 at 02:53
  • Yeah, you make sure you don't lose data the same way TCP does -- you implement retransmissions, acknowledgements, transmit pacing, and so on. – David Schwartz Sep 06 '11 at 14:24
  • I am working on making udp reliable. How can I set the ack flag on a package for example? Also on the client how can I see if a received package has a flag turn on? That is all that I am missing to solve this question.... Making udp reliable conbined with udp punch holing will be the same thing as "tcp punch holing" – Tono Nam Sep 07 '11 at 04:43
  • You can, for example, make the first byte of the packet a 'flags byte'. You can make a 1 represent ACK. So if the 1 bit is set in the first byte, it's an ACK packet. You can do it any way that you want. – David Schwartz Sep 07 '11 at 04:52
  • Lets say that the byte array Data1 has a length of 2048. When I call the client.Send(Data1) how many packages will be sent? What is the maximum number of bytes that I can send per package so that I can try what you said? – Tono Nam Sep 07 '11 at 05:01
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/3228/discussion-between-david-schwartz-and-tono-nam) – David Schwartz Sep 07 '11 at 05:36
  • If you have udp punch holing already I think you just need to switch protocols and use the same address. – TheCodeKing Sep 08 '11 at 07:30
2

There is an excellent article about UDP and TCP hole punching techniques.

http://www.brynosaurus.com/pub/net/p2pnat/

However, you need a well-known rendezvous server for this hole punching technique and I don't think you want to set it up.

By the way, you will want to double-check your company's policy about having your own server in the office. For security, I don't think a company allows an employee to set his or her own server inside.

young
  • 2,163
  • 12
  • 19
  • your link was very helpful. I believe I did what you mentioned on your link. I do not understand why it does not work. Take a look at my update... – Tono Nam Sep 05 '11 at 19:30
2

You could write your own proxy:

Server: Listen on 1300 for connection from A, and on 1301 for connection from B. Keep a list of both connections, when you have at least one of each, create a proxy object. At this time you signal your connection from B that you have a connection, which could be a signal byte or a port and even address to connect to. After that when you get data from A, send it to B. When you get data from B, send it to A.

Computer B: Program maintains a connection to port 1301 on Server. If the connection ever drops, re-establish it. When you receive a signal (could have address and port or just be an "I have a connection" byte), create a connection to the desired port and store the two connections in a proxy object. When you receive data from one, send it to the other. Since you're using that connection, establish a new connection to port 1301 on the Server to handle more.

You'll have to handle dropped connections of course, sending a keep-alive signal between the always-open pending connection between B and the Server will help.

Here's a sample class I wrote a long time ago to do the proxying. I don't have time to clean it up, but if you see TcpProxy that is a parent class that accepts a connection, the Client is the accepted connection and RemoteEndPoint is the end point to connect to. It also writes the data to a file and does some other stuff you can ignore.

Jason Goemaat
  • 28,692
  • 15
  • 86
  • 113