As soon as you start listening on an unassigned port (0), it will be assigned by the operating system (or, more precisely, by the TCP/IP stack). Since the stack manages all the ports, it can assign a free one.
So just start to listen on your connection and then check the port in the LocalEndpoint property to pass it to the client. The TcpListener documentation contains more information about this.
If you need to find a free one in a range, you just have to loop over the full range and try to start listening on each one. If you succeed, you found a free port and you can exit your loop; if not, just continue with the loop. This is the only reliable way to do it because otherwise you can run into a race condition with other processes or even threads of yours which both evaluate the same free port and the first to use it "wins", while the other code will not be able to use the port.