1. 9
  1.  

  2. 1

    0.0.0.0 technically means something like “null” or “no address”, but when used as a listening address, it’s interpreted as “Listen on ALL Addresses”.

    As far as I understand, 0.0.0.0 means all IPv4 interfaces, and a listener bound to that address will not respond to IPv6 requests. Am I mistaken?

    The article presents a story that’s not totally consistent with my understanding. My understanding is that a listen address (string) goes through a resolution process before a listening socket is opened. The first step of that process is to parse the string, and map it to one or more network interfaces — :80 should map to all available interfaces, 0.0.0.0:80 to all interfaces speaking IPv4, and so on. The next step is to parse the host (IP) portion of the listen address, and use it as a sort of filter against the relevant interfaces, with some special treatment for special addresses — for example “localhost” addresses like 127.0.0.1:80 may also accept connections made to equivalent addresses like 127.1.2.3:80.

    Finally, if I’ve configured port forwarding on my router and my router’s public IP address is 97.116.6.53 . . . Then I could make an application only listen for connections coming from the internet by telling it to listen on 97.116.6.53:80.

    Can an application bind to a listen address for an IP which is not owned by one of its interfaces? I can’t call Go’s net.Listen with my router’s public IP, for example…

    1. 1

      As far as I understand, 0.0.0.0 means all IPv4 interfaces, and a listener bound to that address will not respond to IPv6 requests. Am I mistaken?

      The article presents a story that’s not totally consistent with my understanding. My understanding is that a listen address (string) goes through a resolution process before a listening socket is opened.

      Binding a socket to an address is not done with a string, so any parsing would happen at a higher level. However, in general, listening on multiple address families isn’t possible for most kinds of socket. v4 and v6 on one TCP listening socket is achieved by having the OS map IPv4 connections into a virtual IPv6 address space that’s reserved just for this.

      The next step is to parse the host (IP) portion of the listen address, and use it as a sort of filter against the relevant interfaces

      Most sockets are really bound to addresses, not interfaces; though it’s possible to do either on popular platforms, the interface thing is an advanced feature for niche uses.

      for example “localhost” addresses like 127.0.0.1:80 may also accept connections made to equivalent addresses like 127.1.2.3:80

      This shouldn’t happen. Addresses in 127.0.0.0/8 are all the local host, but they aren’t the same address.

      Can an application bind to a listen address for an IP which is not owned by one of its interfaces?

      On systems with the IP_FREEBIND socket option, yes. But it won’t do anything until that IP becomes owned by a local interface—otherwise the system’s networking layer won’t know that traffic for that address needs to be handled locally.

      1. 2

        Thanks for the info, I will update it. I need a better example for the public internet address, like a server in a rack at a datacenter that has a public internet cidr block pointed at it. Then different apps on that server can listen on different addresses within that block.

        1. 1

          A listener binds to a specific address. That address can have a host portion expressed as e.g. 0.0.0.0 but AFAIK cannot have a host portion expressed as a CIDR block e.g. 192.168.1.0/24. So I don’t think CIDR block assignments or expressions have any relationship to the values accepted by listeners. But I may be wrong!

          1. 1

            I wasn’t talking about a listener having a cidr block, I was talking about a network interface having a cidr block (say, this machine has all IPs 123.45.6.1 to 123.45.6.255 or something like that). And then individual application processes may “claim” one of those IPs by listening on it, say 123.45.6.11 or 123.45.6.201. I’m pretty sure that’s a thing that can happen?

            1. 1

              I don’t believe it is possible for one interface to claim an entire CIDR block, modulo some middle-box shenanigans. My understanding is that a network interface, uniquely identified by a MAC address, can claim exactly one address per network-layer protocol (IPv4, IPv6, etc.)

              I could be under-informed. Can you tell me the steps to get my Linux box to claim 10.1.1.0/24?

              1. 2

                I don’t know the details but I think you are right. I think what I was talking about will only work if your machine has a bunch of different network interfaces that all have different addresses. I removed that part from the article, thanks for noticing the issue there.

        2. 1

          Binding a socket to an address is not done with a string, so any parsing would happen at a higher level.

          The C API uses struct sockaddr_t, but effectively zero languages expose those struct details to the programmer, and instead offer string-based APIs. This definitely introduces potential ambiguity! But my general understanding is those string-to-sockaddr parsing functions are pretty standard. Am I mistaken?

          This shouldn’t happen. Addresses in 127.0.0.0/8 are all the local host, but they aren’t the same address.

          If I bind a listener to 127.0.0.1:1234 and then run nc 127.0.0.2 1234 it has been my consistent experience that the listener will accept the connection. Is this not standard behavior?