2

I am building a chrome app and created a UDP socket via the chrome socket api.

Is there a way to retrieve your own IP address without using an external service? What I mean by "own IP address": Both client and server are on the same network. The chrome app needs to answer to a UDP broadcast with it's own local IP address.

There is actually a chrome socket API for exactly that use-case. But unfortunately I only receive the following callback object: Object {paused: false, persistent: false, socketId: 17}, which misses the localAddress attribute. It is an (optional) attribute in the SocketInfo object according to the documentation. This is in essence the code I am running:

chrome.sockets.udp.create({}, function(socketInfo){
    chrome.sockets.udp.getInfo(socketInfo.socketId, function (detailedInfo){
        ipAddress = detailedInfo.localAddress;
        console.debug(detailedInfo); // containts no `localAddress`
    });
});

I also do not think that I am missing any manifest-permissions as there are no special permissions described in the API documentation. This is what I use:

"sockets": {
  "udp": {
    "send": "*",
    "bind": "*"
  }
}

When I use Python I can achieve that goal as follows:

import socket
ip_address = socket.gethostbyname(socket.gethostname())

Any help would be great!

m3o
  • 3,881
  • 3
  • 35
  • 56
  • If the calling machine has multiple network interfaces, `gethostbyname()` can return multiple local IPs. – Remy Lebeau Dec 18 '14 at 02:28
  • Wrong - It will only return exactly one IP address. Python picks up the interface which is currently the "highest" in the interface list, which is provided by the OS. This is exactly what I want and 99% of all other users as well. – m3o Dec 18 '14 at 02:36
  • Trust me when I say that the "highest" interface in the OS list is NOT always the correct one, and besides that, `gethostbyname()` performs a DNS lookup, which can report unexpected results in some circumstances, even for a local hostname. The `gethostbyname(gethostname())` combination has been widely abused for years because of a misconception that it always returns a local IP, and that is not always true. That is why `network.getNetworkInterfaces()` exists, to get the correct and accurate local IPs without involving DNS. – Remy Lebeau Dec 18 '14 at 02:43

3 Answers3

4

turns out that I have been using the wrong API. For my use case I needed to use chrome.system.network.getNetworkInterfaces.

This will return an array of all interfaces with their IP address.

This is my sample code:

chrome.system.network.getNetworkInterfaces(function(interfaces){
    console.log(interfaces);
});

manifest-permissions:

"permissions": [
  "system.network"
],

Considering the comments a perfect solution is not easy to provide, as one has to find the correct interface to the UDP-port.

At this point the only way to perfectly match the interface one has to bind all addresses for all interfaces given by getNetworkInterfaces. Then you know exactly which interface was used to receive the call and you can respond with the correct IP address.

m3o
  • 3,881
  • 3
  • 35
  • 56
  • That does not tell you which interface is actually receiving the UDP broadcast packet. When replying, you should be specifying the IP of the interface that received the packet, since that is the interface that is connected to the LAN that the broadcast occurred on. – Remy Lebeau Dec 18 '14 at 01:55
  • That's correct - Someone will have to come up with a perfect solution. For my case the interface is obvious and this solution works for me. If I will find a better solution for the interface matching I will post it - or for that matter endorse someone else's solution... – m3o Dec 18 '14 at 01:57
  • Your solution fails if the machine has multiple interfaces installed, which is very common nowadays (virtual machines, multiple networks, WiFi vs Wired networks, etc). – Remy Lebeau Dec 18 '14 at 02:10
  • As I said - I understand your objection. The solution will not be perfect for everyone. But at least in my case (also with multiple interfaces) it is very obvious, based on the sender which of the interfaces is the correct one for me. You are welcome to find a better solution. In the meantime I think some people will already be thankful with this post. It is also valid as in it solved the basic part of my question - to find ones own IP address without the use of an external service in the same manner as Python does. The tricky part is now for everyone else to infer the correct interface. – m3o Dec 18 '14 at 02:15
  • See my answer for a possible solution. – Remy Lebeau Dec 18 '14 at 02:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/67176/discussion-between-marco-and-remy-lebeau). – m3o Dec 18 '14 at 02:48
0

An unconnected socket does not have a local address yet, unless it is specifically bound to an address . It only gets a local and remote address once the socket is connected (TCP) or you send data through the socket (UDP). And it only gets the IP address of the local machine, whereas an external service sees the internet-facing external address of the router if you are behind some NAT router (i.e. most home users).

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • I think your answer might have given me what I wanted to know. I am running this application in a local network (both, client and server, will be on the same network). I am receiving a UDP broadcast message, to which I will respond with my own IP address. So this will be meaning full enough for me - I will write back once I know if it worked or not. – m3o Dec 17 '14 at 20:53
  • so close... I did wait with the `getInfo` call until I had received a first package. And yes, it now finally has the attribute `localAddress`. Unfortunately its `0.0.0.0` - even when I check back after my `send`... the full Object now is `Object {localAddress: "0.0.0.0", localPort: 22222, paused: false, persistent: false, socketId: 21}` – m3o Dec 17 '14 at 21:09
  • That is because your UDP socket is not bound to any specific local IP when you create it, thus it listens on and receives packets on all local IPs. That is what `"0.0.0.0"` represents. – Remy Lebeau Dec 18 '14 at 02:08
-1

The callback you provide to udp.create() is called when the socket has been initially created, not when the socket receives packets. At creation time, the socket is not associated with any localAddress or localPort yet. You have to call udp.bind() to establish the specific localPort (and optionally a specific localAddress) that the socket will listen for packets on. If you bind() to "0.0.0.0" then the socket will listen on all local IPs.

When a new packet arrives, the udp.onReceive event is triggered. The packet was received by a specific localAddress, however the Chrome API does not provide a means of directly querying which localAddress received the packet (the underlying recvfrom() socket function does not provide that information). To discover the receiving local IP, you would have to either:

  1. bind the socket to a specific localAddress, as that will be the only local IP that can trigger the onReceive event for that socket.

  2. check the list of interfaces reported by chrome.system.network.getNetworkInterfaces(). If 1 interface is reported, that will be the interface receiving all packets, so you can use its address. However, if 2+ interfaces are reported, you will have to parse the network prefix from the packet's remoteAddress and compare that value to the prefix of each reported interface until you find a match (assuming the sender is broadcasting from the same network subnet that the local machine is connected to, and not broadcasting across subnet boundaries).

That being said, all of this is only relevant if you need to put your local IP in the broadcast reply's data payload. Say there are 3 local interfaces, and the broadcast packet is received on interface 2. Replying with the localAddress of interface 1 or 3 would obviously be wrong, as they are on different networks than the broadcaster. However, if you DO NOT need to put your localAddress in the reply's payload, then the broadcaster can simply look at the remoteAddress of the reply to know what your IP address is. Then you do not need to figure out your local IP at all, the OS will handle everything for you when you send the reply to the remoteAddress/remotePort that you received the broadcast from.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770