Pretending port zero is a normal one

Speaking the TCP protocol, we communicate between “ports” in the local and remote ends. Each of these port fields are 16 bits in the protocol header so they can hold values between 0 – 65535. (IPv4 or IPv6 are the same here.) We usually do HTTP on port 80 and we do HTTPS on port 443 and so on. We can even play around and use them on various other custom ports when we feel like it.

But what about port 0 (zero) ? Sure, IANA lists the port as “reserved” for TCP and UDP but that’s just a rule in a list of ports, not actually a filter implemented by anyone.

In the actual TCP protocol port 0 is nothing special but just another number. Several people have told me “it is not supposed to be used” or that it is otherwise somehow considered bad to use this port over the internet. I don’t really know where this notion comes from more than that IANA listing.

Frank Gevaerts helped me perform some experiments with TCP port zero on Linux.

In the Berkeley sockets API widely used for doing TCP communications, port zero has a bit of a harder situation. Most of the functions and structs treat zero as just another number so there’s virtually no problem as a client to connect to this port using for example curl. See below for a printout from a test shot.

Running a TCP server on port 0 however, is tricky since the bind() function uses a zero in the port number to mean “pick a random one” (I can only assume this was a mistake done eons ago that can’t be changed). For this test, a little iptables trickery was run so that incoming traffic on TCP port 0 would be redirected to port 80 on the server machine, so that we didn’t have to patch any server code.

Entering a URL with port number zero to Firefox gets this message displayed:

This address uses a network port which is normally used for purposes other than Web browsing. Firefox has canceled the request for your protection.

… but Chrome accepts it and tries to use it as given.

The only little nit that remains when using curl against port 0 is that it seems glibc’s getpeername() assumes this is an illegal port number and refuses to work. I marked that line in curl’s output in red below just to highlight it for you. The actual source code with this check is here. This failure is not lethal for libcurl, it will just have slightly less info but will still continue to work. I claim this is a glibc bug.

$ curl -v http://10.0.0.1:0 -H "Host: 10.0.0.1"
* Rebuilt URL to: http://10.0.0.1:0/
* Hostname was NOT found in DNS cache
* Trying 10.0.0.1...
* getpeername() failed with errno 107: Transport endpoint is not connected
* Connected to 10.0.0.1 () port 0 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.38.1-DEV
> Accept: */*
> Host: 10.0.0.1
>
< HTTP/1.1 200 OK
< Date: Fri, 24 Oct 2014 09:08:02 GMT
< Server: Apache/2.4.10 (Debian)
< Last-Modified: Fri, 24 Oct 2014 08:48:34 GMT
< Content-Length: 22
< Content-Type: text/html

 

<html>testpage</html>

Why doing this experiment? Just for fun to to see if it worked.

(Discussion and comments on this post is also found at Reddit.)

10 thoughts on “Pretending port zero is a normal one”

  1. Well you see, that is the whole point. Just as 0.0.0.0 is an ip address reserved for meaning to bind to any address. port 0 is reserved for meaning bind to any port.

  2. Quite obviously bind on port 0 means that, yes, I just don’t understand why an otherwise legitimate port number was taken to get that meaning. It seems like an odd choice to me. But then of course it was done in a different time.

    (I’ll just pretend you didn’t mention that thing about an attack vector because I find it too stupid.)

  3. 0.0.0.0 isn’t reserved for “any address”. It just happens not to be a valid host address anyway.

  4. > I see no reason for publishing this other than giving people interested in trying to spread malware yet another attack vector.

    Somehow only the second stupidest thing I’ve read today.

    > 0.0.0.0 isn’t reserved for “any address”. It just happens not to be a valid host address anyway.

    It’s used to mean any address though, in many contexts. Binding to it results in receiving all ipv4 traffic you have interfaces for, putting it in a routing table routes all traffic, etc.

  5. In routing, you don’t really use 0.0.0.0 as such. You use 0.0.0.0/0, i.e. you need the netmask. That 0.0.0.0/0 value isn’t a special case either, it’s parsed in exactly the same way as e.g. 192.168.0.0/16.

    The bind() case is different, but that’s an API decision, not really a protocol matter.

  6. I work for an ISP and we block incoming and outgoing traffic on port 0 because it’s almost always a misconfigured or broken service. I haven’t found any valid uses of port 0. Most often it’s used by malware. I believe a lot of large ISPs block port 0, so it’s practical use on the Internet is probably not very high.

  7. Scott: I’m convinced countless ISPs, routers and stuff also block traffic to this port. But then again a large portion of the net blocks everything that isn’t TCP over port 80, so I’m not really suggesting traffic to port 0 would magically have a high success ratio. On the contrary, it is probably the port with the _least_ ability to work across the Internet.

Comments are closed.