35

I can't seem to find anything that tells me if a port in my router is open or not. Is this even possible?

The code I have right now doesn't really seem to work...

private void ScanPort()
{
    string hostname = "localhost";
    int portno = 9081;
    IPAddress ipa = (IPAddress) Dns.GetHostAddresses(hostname)[0];
    try
    {
        System.Net.Sockets.Socket sock =
                new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork,
                                              System.Net.Sockets.SocketType.Stream,
                                              System.Net.Sockets.ProtocolType.Tcp);
        sock.Connect(ipa, portno);
        if (sock.Connected == true) // Port is in use and connection is successful
            MessageBox.Show("Port is Closed");
        sock.Close();
    }
    catch (System.Net.Sockets.SocketException ex)
    {
        if (ex.ErrorCode == 10061) // Port is unused and could not establish connection 
            MessageBox.Show("Port is Open!");
        else
            MessageBox.Show(ex.Message);
    }
}
ympostor
  • 909
  • 7
  • 16
Yuki Kutsuya
  • 3,968
  • 11
  • 46
  • 63

12 Answers12

58

Try this:

using(TcpClient tcpClient = new TcpClient())
{
    try {
        tcpClient.Connect("127.0.0.1", 9081);
        Console.WriteLine("Port open");
    } catch (Exception) {
        Console.WriteLine("Port closed");
    }
}

You should probably change 127.0.0.1 to something like 192.168.0.1 or whatever your router's IP address is.

Sergik666
  • 127
  • 2
  • 6
Clinton Ward
  • 2,441
  • 1
  • 22
  • 26
  • It says that it can not connect even if the port is open. – Yuki Kutsuya Aug 07 '12 at 14:12
  • 1
    that means nothing is listening on that port. Make sure your router is port forwarding to your pc and have a program open and listening on that port and it will connect. Also you should try to connect using your outside world address. Look up my ip in google and use that ip address. – Clinton Ward Aug 07 '12 at 14:35
  • I did, but then again, is it possible to detect if that port is open without having a program that uses the port? – Yuki Kutsuya Aug 07 '12 at 20:50
  • I think if you want to delve into the complexities of the port states you should look at using Nmap. This program can tell you what is running on the port what firewall is allowing access etc. – Clinton Ward Aug 08 '12 at 01:27
37

A better solution where you can even specify a timeout:

using System;
using System.Net.Sockets;

// ...

bool IsPortOpen(string host, int port, TimeSpan timeout)
{
    try
    {
        using(var client = new TcpClient())
        {
            var result = client.BeginConnect(host, port, null, null);
            var success = result.AsyncWaitHandle.WaitOne(timeout);
            client.EndConnect(result);
            return success;
        }
    }
    catch
    {
        return false;
    }
}

And, in F#:

open System
open System.Net.Sockets

let isPortOpen (host: string) (port: int) (timeout: TimeSpan): bool =
    try
        use client = new TcpClient()
        let result = client.BeginConnect(host, port, null, null)
        let success = result.AsyncWaitHandle.WaitOne timeout
        client.EndConnect result
        success
    with
    | _ -> false

let available = isPortOpen "stackoverflow.com" 80 (TimeSpan.FromSeconds 10.)
printf "Is stackoverflow available? %b" available
Redline
  • 441
  • 8
  • 20
ympostor
  • 909
  • 7
  • 16
  • How performant is this method? Especially in F#? I'm working on a thesis for a network protocol and part of the (pre)process is to compose a list of available ports. – czifro Oct 23 '16 at 19:41
  • 1
    it should be as performant as the C# one... but measure it yourself just in case? – ympostor Nov 08 '16 at 05:00
  • 1
    Love the F# implementation, thank you for providing that. – Max Young Jul 23 '18 at 14:37
  • Think there might be a problem with this approach, because if the connection failed, then you will keep trying to end the connection.... and that one will fail. – HellBaby Sep 08 '21 at 14:23
  • 2
    `client.EndConnect` will wait for 20 seconds, (default timeout) so this does not work – Alex from Jitbit Nov 13 '21 at 09:03
4

There is no way to know if the port is forwarded in your router, except if there is a program listening on that port.

As you may see in the Clinton answer, the .Net class being used is TcpClient and that is because you are using a TCP socket to connect to. That is the way operating systems make connections: using a socket. However, a router just forwards the packets (layer 3 of the OSI Model) in or out. In your case, what your router is doing is called: NAT. It is one public IP shared by a one or more private IPs. That´s why you are making a port forwarding.

There may be a lot of routers in the path of the packets, and you will never know what had happened.

Let´s imagine you are sending a letter in the traditional way. Perhaps you can write in the letter that the receiver must answer, in order to check he/she is there (you and the receiver are the sockets). If you receive an answer you will be sure he/she is there, but if you don´t receive anything you don´t know if the mailman (in your case the router) forgot to deliver the letter, or the receiver hadn´t answered. You would also never know if the mailman has asked a friend to deliver that letter. Moreover, the mailman won´t open the letter in order to know he/she may answer because you are waiting for a reply. All you may do is wait some time to receive the answer. If you don´t receive anything in that period you will assume that the receiver isn´t where you sent the letter. That is a "timeout".

I saw an answer mentioning the nmap software. It´s really a very good and complex soft, but I think it will work in the same way. If there is no app listening in that port, there is no way to know if it is open or not.

Please, let me know if I was clear.

KirstieBallance
  • 1,238
  • 12
  • 26
Ignacio
  • 910
  • 2
  • 12
  • 24
  • 1
    Nice answer, I felt I was back in Networking 101 again haha, in addition to this, more specifically we are talking about the router's firewall (not routing itself...), nowadays a common closed port action is to drop the packet, not to reject it (because they would have to reject too many!), so, in the example, maybe your receiver is "actively" discarding your letter, not even telling the mailman to return it, so you won't get something like "receiver says that doesn't want your letter" confirmation, but I also guess you knew all of these things and as I, you came here for Clinton's answer =P – Gabriel G Mar 23 '20 at 15:03
3

If you're connecting to the loopback adapterlocalhost or 127.0.0.1 (there's no place like 127.0.0.1!), you're unlikely to ever go out to the router. The OS is smart enough to recognize that it's a special address. Dunno if that holds true as well if you actually specify your machine's "real" IP address.

See also this question: What is the purpose of the Microsoft Loopback Adapter?

Also note that running traceroute localhost (tracert localhost in Windows) shows that the only network node involved is your own machine. The router is never involved.

Community
  • 1
  • 1
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
3

Other than BeginConnect you can also use ConnectAsync (added in .NET Framework 4.5 I think?).

TcpClient client = null;

try {
    client = new TcpClient();
    var task = client.ConnectAsync(host, port);
    if (task.Wait(timeout)) {//if fails within timeout, task.Wait still returns true.
        if (client.Connected) {
            // port reachable
        }
        else
            // connection refused probably
    }
    else
        // timed out
}
catch (Exception ex) {
    // connection failed
}
finally {
    client.Close();
}

Full project is here because paping refuses to run and I couldn't find another "ping host:port" tool to my likes.

Carl Chang
  • 119
  • 5
1

A port forward on the router cannot be tested from inside the LAN, you need to connect from the WAN (internet) side to see if a port forward is working or not.

Several internet sites offer services to check if a port is open:

What's My IP Port Scanner

GRC | ShieldsUP!

If you want to check with your own code, then you need to make sure the TCP/IP connection is rerouted via an external proxy or setup a tunnel. This has nothing to do with your code, it's basic networking 101.

1
public static bool PortInUse(int  port)
{
    bool inUse = false;

    IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
    IPEndPoint [] ipEndPoints = ipProperties.GetActiveTcpListeners();


    foreach(IPEndPoint endPoint in ipEndPoints)
    {
        if(endPoint.Port == port)
        {
            inUse = true;
            break;
        }
    }


    return  inUse;
}
lazzy_ms
  • 1,169
  • 2
  • 18
  • 40
Ravi Kumar G N
  • 396
  • 1
  • 3
  • 11
  • 2
    Please add a description of what your code does and what the difference between yours and the other answers is. – Hille Jun 19 '19 at 11:05
  • For checking which ports are open on the local machine this is best answer. It also handles the various states that connections can be in (e.g. open, accepted, closing etc.) – JoeS May 28 '20 at 19:45
0

For me, I needed something blocking until the connection to the port is available or after a certain amount of retries. So, I figured out this code:

public bool IsPortOpen(string host, int port, int timeout, int retry)
{
    var retryCount = 0;
    while (retryCount < retry)
    {
        if (retryCount > 0)
            Thread.Sleep(timeout);

        try
        {
            using (var client = new TcpClient())
            {
                var result = client.BeginConnect(host, port, null, null);
                var success = result.AsyncWaitHandle.WaitOne(timeout);
                if (success)
                    return true;

                client.EndConnect(result);
            }
        }
        catch
        {
            // ignored
        }
        finally { retryCount++; }
    }

    return false;
}

Hope this helps!

mathpaquette
  • 406
  • 4
  • 16
0

also you can use ConnectAsync like

public async Task<bool> IsIPAndPortOpen(string hostOrIPAddress, int port, TimeSpan timeOut)
        {
            try
            {
                using (var client = new TcpClient())
                {
                    var ct = new CancellationTokenSource(timeOut).Token;
                    await client.ConnectAsync(hostOrIPAddress, port, ct);
                    return true;
                }
            }
            catch
            {
                return false;
            }
        }
Akbar Asghari
  • 613
  • 8
  • 19
0

I have created a method:

public bool CheckPortAvailability(int port)
   {
        if (IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Select(p => p.Port).Contains(port))
        {
            return false;
        }

        if (IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections().Select(p => p.LocalEndPoint.Port).Contains(port))
        {
            return false;
        }

        // Linux - it should always be true because we have already returned false for ports thats are in use
        // Windows - some ports are reserved by Windows, you can see them using "netsh interface ipv4 show excludedportrange protocol=tcp"
        // also there are some other ports on Windows on which we can not start TCP server for some reason
        // using only TryBindTCPServer method is not enough on Windows, because in some cases it allows to start TCP server on already taken ip and port
        if (TryBindTCPServer(IPAddress.Any, port) && TryBindTCPServer(IPAddress.IPv6Any, port))
        {
            return true;
        }

        return false;
    }

private bool TryBindTCPServer(IPAddress localAddr, int port)
    {
        var tcpServer = new TcpListener(localAddr, port);
        try
        {
            tcpServer.Start();
        }
        catch (SocketException)
        {
            return false;
        }

        tcpServer.Stop();
        return true;
    }

On my test environment on Linux, ports numbers I got using IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners() and IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections() methods was exactly the same as ports for which TryBindTCPServer(IPAddress.Any, port) && TryBindTCPServer(IPAddress.IPv6Any, port) is false, that is expected behavior, and means that we don't have to mix both solutions.

On Windows...
We can start TcpListener on a few already taken port(on the same IP address)enter image description here
We cannot start TcpListener on some free ports. Most of them are reserved by windows, see https://superuser.com/questions/1486417/unable-to-start-kestrel-getting-an-attempt-was-made-to-access-a-socket-in-a-way or https://ardalis.com/attempt-made-to-access-socket/. enter image description here

But there are some that are not in use, not reserved and we still cannot start TcpListener on them (If somebody knows why please let me know), in my case: enter image description here

So I think that one of the best solution on Windows is to mix both, trying to start TcpListener and checking already taken ports.
The code I was using for testing:

using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;

static bool CanStartServer(int port)
{
    var ip = IPAddress.Any;
    var tcpServer = new TcpListener(ip, port);
    try
    {
        tcpServer.Start();
    }
    catch (SocketException e)
    {
        return false;
    }
    tcpServer.Stop();

    ip = IPAddress.IPv6Any;
    tcpServer = new TcpListener(ip, port);
    try
    {
        tcpServer.Start();
    }
    catch (SocketException e)
    {
        return false;
    }
    tcpServer.Stop();


    return true;
}

var connections = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections().Select(x => x.LocalEndPoint.Port).Distinct().OrderBy(x => x).ToList();
var listeners = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Select(x => x.Port).Distinct().OrderBy(x => x).ToList();

Console.WriteLine("Listeners:");
Console.WriteLine(string.Join(",  ", listeners));
foreach (var port in listeners)
{
    if (CanStartServer(port))
    {
        Console.WriteLine("TCP Listener starts correctly on port: " + port);
    }
}

Console.WriteLine("Connections:");
Console.WriteLine(string.Join(",  ", connections));
foreach (var port in connections)
{
    if (CanStartServer(port))
    {
        Console.WriteLine("TCP Listener starts correctly on port: " + port);
    }
}
    
connections.AddRange(listeners);
for (var i = connections.Max(); i >= 1024; i--)
{
    if (i >= 50000 && i <= 50059) continue;
    if (i >= 80 && i <= 80) continue;
    if (i >= 5357 && i <= 5357) continue;
    if (i >= 8884 && i <= 8884) continue;
    if (i >= 50866 && i <= 50965) continue;
    if (i >= 50966 && i <= 51065) continue;
    if (i >= 52658 && i <= 52757) continue;
    if (i >= 52858 && i <= 52957) continue;
    if (i >= 53058 && i <= 53157) continue;
    if (i >= 53158 && i <= 53257) continue;
    if (i >= 53258 && i <= 53357) continue;
    if (i >= 53358 && i <= 53457) continue;
    if (i >= 53629 && i <= 53728) continue;
    if (i >= 54830 && i <= 54929) continue;
    if (i >= 55030 && i <= 55129) continue;
    if (i >= 55130 && i <= 55229) continue;
    if (i >= 55230 && i <= 55329) continue;
    if (i >= 55330 && i <= 55429) continue;
    if (i >= 55430 && i <= 55529) continue;
    if (i >= 55530 && i <= 55629) continue;
    if (i >= 64120 && i <= 64120) continue;
    if (i >= 64121 && i <= 64121) continue;
    if (i >= 64122 && i <= 64122) continue;
    if (connections.Contains(i))
    {
        continue;
    }

    if (!CanStartServer(i))
    {
        Console.WriteLine("TcpListener cannot start on port: " + i);
    }
}
Szynkie
  • 59
  • 3
-1
public string GetAvailablePort()
        {int startingPort=1000;
            string portnumberinformation = string.Empty;
            IPEndPoint[] endPoints;
            List<int> portArray = new List<int>();
            IPGlobalPr`enter code here`operties properties = IPGlobalProperties.GetIPGlobalProperties();`enter code here`


            //getting active tcp listners 
            endPoints = properties.GetActiveTcpListeners();
            portArray.AddRange(from n in endPoints
                               where n.Port >= startingPort
                               select n.Port);    

            portArray.Sort();

            for (int i = 0; i < portArray.Count; i++)
            {
                if (check condition)
                {
                    do somting
                }
            }

            return portnumberinformation;
        }
  • 3
    Please add a description of what your code does and what the difference between yours and the other answers is. – Hille Jun 19 '19 at 11:05
-4

If it is Router the simplest way to check it through online services like

You can also try using telenet to chek wether port is accessible or not

telenet [ip-address] [port] 
geekonweb
  • 384
  • 4
  • 14