I'm trying to develop an applicaton for p2p communication between two android devices. In order to punch a hole through my NAT(s), I'd need to know my external ip address and port.
To that end, I've developed a java server on GAE to report my "remote" ip address and port. The problem is that on GAE I can get my ip address, but not my port. Without it, I'm unable to successfully punch the hole.
So, my question is what's the best, free method to find out my external IP address and port?
That's a question that has no answer with TCP.
Here's the problem: your "port" is not a fixed value. You don't have "an" external port. You typically get one dynamically assigned for each outbound connection.
As answers you should see from the test sites posted in another answer clearly indicate, it's a moving target (though it may stay stationary for a short time due to the browser using HTTP/1.1 keepalives and actually reusing the same connection, not just the same port)... but if you hit the site repeatedly, you'll see it either drift around randomly, or increment. Trying it from two different web browsers on the same machine, you'd never see the same port number -- the port corresponds to the specific source connection, not the machine sourcing the connection.
Sometimes, you may find that it's the same port number as the port your machine's stack opened for the outbound connection, but even when it is, it doesn't matter, because no traffic should be able to return to your machine on that port unless it is from the IP address and port of the machine to which you made the outbound connection. Any decent network address translating device would never accept traffic from another source IP address and/or port, other than the one you addressed in the outbound connection.
There is no standard, simple, predictable, reliable, or consistent way to punch a hole in TCP NAT and then exploit that hole for a peer-to-per connection. To the extent that such things are possible in a given NAT implementation, that is an implementation that is shoddy, broken, defective, and insecure.
See also: https://www.rfc-editor.org/rfc/rfc5128
Sounds like your app could use a STUN server to get its external address.
Related
I know there needs to be a STUN/ICE/TURN server to find the IP addresses of the peers involved in a WebRTC communication. However, even after IPs are found, how do the peers actually talk to each other independently without having any ports opened?
If you build a website, you usually have to open the ports on your server to have others access your site. What's the magic that is happening in WebRTC that I'm not understanding?
There are several strategies to do this: one possibility is for the client to explicitly open a port via UPnP. I'm not sure if any current WebRTC client does so, but in general networking this is a possibility.
Failing that, the STUN server kicks in. There are several hole punching techniques it can try; read the aforelinked article for the gory details. In short though, a firewall will usually open a port for outgoing traffic (because it needs to receive responses), so by establishing an outgoing connection to a known target and then making note of the port that was opened it is possible to open a port.
Failing even that, a TURN server is necessary. This server is publicly accessible from both peers, even if both peers cannot see each other. The TURN server then will act as a relay between the two. This somewhat negates the point of a P2P protocol, but is necessary in a certain percentage of situations (estimates range around 10%-20%).
The original Question is "what/who creates the sockets?"
The browsers creates the socket and bind them to a local port for you
during the "ICE gathering".
Wether you use any stun/turn server or
not, each candidate generated during the ice gathering has a
corresponding port open.
Those ports are usually open only for 30 mn
after which they are revoked to avoid an attack by someone using old
and/or spoof candidates. These 30mns are not specified in any
specification and are an arbitrary choice by the browser vendor. -
The next question is "how does the remote peer know about which ports are open".
through the ICE mechanism, which for each media will generate potential candidates and send them to the remote peer through your preferred signaling channel.
ICE candidates (which are one line of SDP, really) have a "type". if this type is HOST, then your candidate is a local candidate generated without the use of any stun or turn server. is the type is SRFLX, then you have used a STUN server to add the mapping between your local IP:port and your public IP:port. if your type is RELAY, same thing with a TURN server.
of course, using the local IP:port HOST candidate will fail unless the remote peer is on the same local network.
From the browser and local system point of view, the socket is open on the local IP:PORT anyway. Hence, opening the sockets and finding out on which port a remote peer should connect to connect to the socket are separate problems handled separately.
The Final question is: "can it really work without a STUN server"
Most probably no, unless you are on the same sub network.
Stats shows (http://webrtcstats.com) that even with a STUN server, you still fail in 8% of the case, for the general public. It's much more in enterprise, where you'd better have advanced turn (supporting tunneling through TCP/80 and TLS/443) and even support for HTTP proxy's CONNECT method.
I know that ipchicken.com will tell you your router's ip address and the port it is using for your connection. But can this information be obtained "locally"? (Without relying on a website).
What I want it for is establishing a connection between two random hosts...without a "dedicated server" in the middle. My problem is to reach through the NAT. I think the best bet is a kind of TCP hole punching, where both hosts connect somewhere and then just tell each other (it can be by phone or chat or similar) the current ip address and the port number their routers are using. It should trick the routers into forwarding the packets to the hosts, albeit coming from a different source than they originally connected to.
Is it possible to find the port number your router is using to patch you through in a more local manner than ipchicken.com?
Are there any ideas on other possible approaches to this problem?
EDIT: Setting port forwarding on the router is not an option in this case, as many people (including me) do not have admin powers over their routers and I do not want to impose such a task on the "users" of my application
The router would use a different source port for every outgoing connection, so checking based on an outgoing connection will not work for your use case.
For an incoming connection, i.e., if you want to reach a specific machine behind a NAT device (like a home router), you'll have to explicitly open up some ports on the router and set up forwarding rules. The router would then listen for incoming connections on that port and forward it to a machine:port based on the configured rule.
How you do this would depend on the specific router make/model. Search the web or logon to the admin interface and look around, it should be easy to find. However make sure you understand the security implications of opening up a port on your router!
UPDATE based on edited question:
Without port-forwarding and if both devices are behind NAT, your only solution is to have an intermediary server! If only one of them is behind NAT, you can have that machine initiate the connection.
You could use a Stun server as the external globally reachable server.
I have an application that relies on IP addresses for communication (Domain names simply does not work. :(... )
Its function is to connect to its peer on the other machine and send data over after establishing trust. During the "trust establishing" phase they both exchange their IPs for future communication. They both are behind the two different firewalls and are NATted. One is in our NATted office network and other is in the cloud NATted behind their firewall. The applications knows their respective private IPs and exchange that (the 10.x.xxx.xxx range), when they try to connect back to each other (using the private IPs with range 10.x.xxx.xxx) for transferring data they fail. The connection is TCP and the port range is pretty varied.
I am curious if there is anyway I can hard code (for this one time) a rule (at may be firewall level or some place outside my application) that says if there is a connection being initiated for IP address 10.x.xxx.xxx then redirect it to 205.x.xxx.xxx?
Private IP address ranges like 10.x.y.z are, by their very nature, private.
You can't do any meaningful resolution unless each node in between the endpoints has rules in place to translate these.
Translation is tricky, all the main tools you would use cater for static translation (port forwarding, e.g. where a particular port is forwarded to a particular IP). This is one avenue, but it is a hacky one (it requires you to open lots of ports, procedurally update your router and probably have some sort of broker server to maintain mappings).
Alternatively, you could run the isolated networks over a VPN, which would give your endpoints mutual private IPs which you can use to connect to eachother. It would simply be a case of binding to this new address and communicating across the VPN. This would also potentially encrypt your communication over the internet.
Other possibilities are to use NAT/TCP punchthrough techniques which can allow traversal, but these are really a patch to a broken network topology (Read up on IPv6 to see how this can be alleviated).
Alternatively, you could route all the connections over a proxy, but this will complicate matters compared to a VPN.
To answer the question about hardcoding a rule, port forwarding is the solution here. It will obviously depend on your router configuration for the peer accepting the connection, but this client should have the port target port forwarded to the machine. This will obviously not scale very well and is really shifting to a server/client architecture for one connection!
Depending on your hardware, you may be able to forward a range of ports (if a single port cannot be established) and limit the port forwarding to certain incoming connections (the external IPs).
Information on port forwarding can be found at http://portforward.com/
This sounds a lot like what you'd want out of a VPN. Is there anyway that you could set one up? Basically the Site-To-Site VPN between you and the cloud would say 'oh hey, here is an ip located on the remote network, go ahead and connect through the link'. Would this kind of solution work in your case?
Something along these lines: http://i.msdn.microsoft.com/dynimg/IC589512.jpg
Is there an elegant way to make a program detect a new computer that is connected to the network?
I would like my program to "auto-sense" a new computer being connected on the network (they're on the same network). Like a USB device being connected to the computer.
What I'm doing now is to save a list of all computers in the network from time to time. Another approach is to PING all available IPs on the subnet.
Are there any other elegant approaches?
Thanks!
Listening for ARP requests is the canonical way to do this. Independent of DHCP or not, any connected computer that wishes to communicate with the outside world will have to make an ARP request for the address of the default router. This request will go out as a broadcast, and contain the source interface's MAC and IP adresses.
If the other computer uses DHCP, it will make an ARP request for it's own address as part of duplicate address detection, which is also a broadcast you can snoop on.
(This works more or less the same way for IPv6, except you need to look for neighbor discovery or router soliciation packets instead.)
Like the answer alluded to, if you have a switch to which you can telnet or use SNMP on, you can extract the MAC table. That will give you a list of MAC adresses on each port in the switch. If you want the IP addresses however, you still need to listen for ARP:s.
On the other hand, if you have access to the default gateway on the network, you can also look at the ARP table there. That will give you MAC and IP addresses for anyone that has recently (for different values of recently...) communicated with it.
If you have a managed switch of some kind, you could probably connect to that, that would be a fairly elegant method.
If you're on a domain, you can can get a list of all the machines joined to the domain from the domain controller.
Failing that, all I can think of is either a challenge/response thing (e.g. pinging them) or by detecting traffic sent from them (see this question maybe as a starting point?), neither of which strike me as an elegant approach.
I've noticed recently that I don't have to forward ports for mmorpg's that I play.
I'm thinking about working on a game that people can play online and had a question.
Why is this the case given its a two way socket connection that is constantly sending data back and forth? Doesn't their server need to get through my firewall in order to connect to me?
TCP crash lesson: TCP is a two-way protocol. The challenge is that at least one host needs to initiate. Since within an MMORPG, your own computer is never acting as a server, nobody has to connect to it. All the information about game state is passed through the company's public facing servers that have public facing IP addresses (and hey, maybe they actually use port forwarding there, just to confuse my explanation... but you never have to see their pretty network internals, proxies, and other wizardry.).
Anyway, when you connect to Stackoverflow, you're making one outbound connection that requests data from the server, and then over that same connection you're receiving it back. Same exact scenario, only with a webserver instead of a game.
UPnP allows you to tackle many routers. There's also NAT Punch-Through if you have access to a third party that isn't behind a router.
Either way, port forwarding is only necessary if you wish to act as a server (or the sender in a P2P relationship). A client does not need to forward ports.
You don't need to forward ports to access the web either, despite data coming in as well.
When you make an outgoing TCP connection, your NAT router puts the connection in a table, so that when data comes in, it knows what machine in your LAN to send the packet to.
Everyone mentions TCP, but NAT works for UDP as well: The first outgoing UDP packet associates that source port with the internal IP address, and your NAT device will forward incoming traffic to that port to the correct host on the internal network.
In other words, if your computer requests the connection (outbound) first, the router opens up the port automatically, on the assumption that you're going to want data back. But if you want remote users to connect to your computer without your computer requesting it, the router would normally drop the packets since it wouldn't know where to send them (they were unsolicited). So instead, you need to tell the router to deliver any unsolicited packets at port N to your computer.
Sorry to add another answer so late, and I know one was already accepted, but I personally found the other answers to be more confusing than this simple explanation.