[HN Gopher] The Curious Case of Port 0 (2019) [pdf]
       ___________________________________________________________________
        
       The Curious Case of Port 0 (2019) [pdf]
        
       Author : elvis70
       Score  : 71 points
       Date   : 2021-04-18 11:52 UTC (11 hours ago)
        
 (HTM) web link (dl.ifip.org)
 (TXT) w3m dump (dl.ifip.org)
        
       | nerdponx wrote:
       | > When you open a listening socket on a host and request port 0
       | from the operating system, this call is typically interpreted as
       | a request to return a single, currently unused port to the
       | application
       | 
       | But... why? Surely some kind of separate BIND_UNUSED_PORT
       | operation would have been fine, without needlessly overloading
       | the meaning of "port 0".
        
         | Joker_vD wrote:
         | Having a specific port number to mean "pick a random unused
         | port" is very useful when you run any application that opens a
         | listening TCP socket and takes the port number from the config.
         | More often than not, the default behaviour (when the port is
         | not specified) is to use some hardcoded port number like 5555
         | or something. But what if you want to run two/three/many copies
         | of this app, dynamically, without them interefering with each
         | other? One possibility is to do manual free port detection--but
         | it's inherently racy. Another one is to specify port 0 and get
         | the actual port number from the application by some side
         | channel (say, by reading it from stderr/log file).
         | 
         | Now, I assure you that if this "some kind of separate
         | BIND_UNUSED_PORT" operation was available in the Berkeley
         | socket API from the start, it would be mostly unused, people
         | would've just used normal bind() instead (it's way simpler), so
         | the latter option simply becomes impossible: you have to
         | manually pick the free ports for temporary servers. In fact,
         | there are some existing applications that actively refuse to
         | listen on port zero, for example, "ssh -D 0" doesn't work for
         | some reason (patching it to remove the zero check breaks
         | nothing, everything keeps working properly), and they're
         | somewhat annoying to use transiently.
        
           | monocasa wrote:
           | I would have just made sin_port be a 32 bit number, with
           | UNUSED_PORT being some value in the otherwise invalid range,
           | and the others giving you EINVAL on bind(3).
        
             | Joker_vD wrote:
             | Or you could spare those 2 bytes at a cost of being unable
             | to listen on one out of 65536 ports. In 1983, this tradeoff
             | absolutely made sense: 64K ports should be enough for
             | everyone.
        
               | monocasa wrote:
               | Even in 1983, the kinds of machines expecting to be
               | networked with IP could spare the occasional couple bytes
               | here and there if it meant being able to signal out of
               | band information to the stack without carving out a set
               | of the wire formats as unencodable.
        
           | nerdponx wrote:
           | I guess, but what if it was just a call to bind_unused()
           | instead of bind()?
        
             | Joker_vD wrote:
             | Most programs would simply use bind(), instead of having a
             | more complicated option parsing and condition around
             | bind()/bind_unused():                   sockaddr_in
             | sockaddr = { 0 };         sockaddr.sin_port =
             | HARDCODED_PORT;         // other fields defaulted...
             | // option parsing and filling sockaddr structure...
             | if (has_port_number && flag_use_random_port) {
             | error(...);             exit(1);         }         if
             | (has_port_number) {             bind(s, sockaddr);
             | } else {             bind_unused_port(s, sockaddr);
             | }
             | 
             | vs.                   sockaddr_in sockaddr = { 0 };
             | sockaddr.sin_port = HARDCODED_PORT;         // other fields
             | defaulted...                  // option parsing and filling
             | sockaddr structure...              bind(s, sockaddr);
             | 
             | Yeah, people would just write the second version. And mind
             | you, the sockaddr argument for bind_unused() still would
             | have a local address to bind to, so what exactly is gained?
             | Difference between 65535 or 65536 ports available doesn't
             | warrant complicating API in such a manner, IMO.
        
         | toast0 wrote:
         | They could have done something like that, but then you need to
         | pass more than a 16-bit value in for port number. Back when
         | that was a concern, limiting to only 65535 usable ports wasn't
         | a big deal. Now, you probably could use a larger integer and
         | pass a flag to really bind to port zero, other than there's
         | probably a lot of network equipment that will drop it. If you
         | also run on an IPv4 address with a final octet of 0 or 255,
         | you'll have a really hard to reach service.
        
       | theskyo wrote:
       | We need to differentiate 2 things:
       | 
       | * Port 0 and DDoS: This is usually just a measurement artifact.
       | Reflection-Amplification attacks create UDP packets larger than
       | the current MTU, which leads to fragmentation and hence packet
       | fragments without a UDP header -- however they are still
       | identified as UDP because the ip.proto field is still 17, i.e.
       | UDP). Interpreting such packets often leads to "port 0" instead
       | of "port None", eg in IPFIX.
       | 
       | * Port 0 in the actual traffic. This has to be done via RAW
       | sockets, since this usually signals the OS to use ANY port
       | (especially if binding). This technique has been used ages ago
       | (20 years? see Gobbler tool) to fingerprint operating systems,
       | because they all responded differently to such packets.
        
       | bombcar wrote:
       | I'm surprised port zero packets aren't just randomly dropped by
       | various internet infrastructure devices. Perhaps they've been
       | burned by reserved things suddenly becoming used.
        
         | zamadatix wrote:
         | Most of the devices on the internet don't even know the packets
         | they are forwarding are TCP/UDP let alone care about which port
         | number is being used.
        
       | tux wrote:
       | Here is a similar article by Daniel Stenberg the "curl" author.
       | 
       | "Pretending port zero is a normal one" (Oct. 25, 2014)
       | 
       | https://daniel.haxx.se/blog/2014/10/25/pretending-port-zero-...
       | 
       | I'm suprised no one has used this port as an attack vector yet.
       | I'm sure many even miss this port in there iptables.
        
         | gumby wrote:
         | According to the posted article it _is_ used for DDOS attacks.
        
       | bernardand wrote:
       | According to the posted article it is used for DDOS attacks.
        
       | andrewnicolalde wrote:
       | Anyone else getting certificate issues?
        
       | WarOnPrivacy wrote:
       | We home-hosted a modestly successful Minencraft server for 4
       | years.
       | 
       | Occasionally, some disgruntled player would aim a booter service
       | at us. Most of those DDoS attacks were aimed at port 0.
        
         | tux wrote:
         | Very interesting, this is first time I heard of DDoS/Zero ^_^
         | Did you keep any logs on this?
        
           | WarOnPrivacy wrote:
           | It's possible. I'll peek around and post back if I find one.
        
       ___________________________________________________________________
       (page generated 2021-04-18 23:01 UTC)