Duo Device Health - Port Allocation Fails Silently

Hi team, the Duo Device Health application (v2.14.0) on Windows 10 Enterprise (10.0.19042.1110) might fail to allocate the listening TCP port in the range 5310x if Hyper-V (and perhaps Docker) is installed - with no indication that anything has failed in the app.
In such a case, when trying to authenticate with Duo 2fa, the 2fa page thinks that the Duo Health app is not running and asks the user first to Start it and then to download and install Duo Health. However, reinstalling the app does not help to unlock the Windows reserved ports and hence the user ends up in an endless troubleshooting loop when the Duo Health app is running, but still, the 2fa page asks the user to install it.

Recommended change:

  • after launching the Duo Device Health app, if the app has failed to allocate a tcp socket, notify the user with a pop-up message that they should contact their IT Support team for a Socket allocation has failed.

Tech details:

At least on my computer, Windows has reserved the port numbers 531xx for its internal use (WinNAT service) and when any app tries to allocate those ports, they fail, as for example, starting a Python HTTP server on port 53101:

C:\Users\REM>python -m http.server 53101
Traceback (most recent call last):
  File "C:\Users\REM\AppData\Local\Programs\Python\Python38-32\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\REM\AppData\Local\Programs\Python\Python38-32\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\REM\AppData\Local\Programs\Python\Python38-32\lib\http\server.py", line 1294, in <module>
    test(
  File "C:\Users\REM\AppData\Local\Programs\Python\Python38-32\lib\http\server.py", line 1249, in test
    with ServerClass(addr, HandlerClass) as httpd:
  File "C:\Users\REM\AppData\Local\Programs\Python\Python38-32\lib\socketserver.py", line 452, in __init__
    self.server_bind()
  File "C:\Users\REM\AppData\Local\Programs\Python\Python38-32\lib\http\server.py", line 1292, in server_bind
    return super().server_bind()
  File "C:\Users\REM\AppData\Local\Programs\Python\Python38-32\lib\http\server.py", line 138, in server_bind
    socketserver.TCPServer.server_bind(self)
  File "C:\Users\REM\AppData\Local\Programs\Python\Python38-32\lib\socketserver.py", line 466, in server_bind
    self.socket.bind(self.server_address)
OSError: [WinError 10013] An attempt was made to access a socket in a way forbidden by its access permissions

The workaround was to turn off the WinNAT service:

C:\Windows\system32>netsh int ip show excludedportrange protocol=tcp

Protocol tcp Port Exclusion Ranges

Start Port    End Port
----------    --------
      4800        4800
      5593        5593
      5985        5985
     47001       47001
     50000       50059     *
     52497       52596
     52597       52696
     52697       52796
     52797       52896
     52897       52996
     52997       53096
     53099       53099     *
     53100       53199
     53200       53299
     53300       53399
     59474       59573

* - Administered port exclusions.


C:\Windows\system32>net stop winnat

The Windows NAT Driver service was stopped successfully.


C:\Windows\system32>netsh int ip show excludedportrange protocol=tcp

Protocol tcp Port Exclusion Ranges

Start Port    End Port
----------    --------
      4800        4800
      5593        5593
      5985        5985
     47001       47001
     50000       50059     *
     53099       53099     *

* - Administered port exclusions.


C:\Users\REM>python -m http.server 53101
Serving HTTP on :: port 53101 (http://[::]:53101/) ...

Keyboard interrupt received, exiting.

and then the Duo Device Health also started to work normally (well, had to kill the existing process that failed to allocate the port and start it again).

Thanks for sharing this, @jozjan. I forwarded it to my colleagues on the Device Health team.