Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find server listening on a specific port on local network

Tags:

c#

networking

tcp

I have a server application. I also have a client application. I am able to establish a tcp connection between the applications when both applications happen to be on the same network. so let's say that the computer running the server application is listening from new connections on port 2121 and it has the LAN ip address 192.168.0.120. On a different computer running the client application I will be able to establish a connection by providing port number 2121 and ip address 192.168.0.120.

Is there a way to find all computers on a network that are listening on port 2121?

One algorithm that I am thinking now is like:

  • get ip address of current computer and lets say it comes out as 192.168.0.145.

  • now most likely the server will be listening on ip addresss 192.168.0.?

  • then ping 192.168.0.1 on port 2121 then 192.168.0.2 on port 2121 ... and then keep going.

I don't know if that method is efficient. moreover there might be a possibility that the server happens to be listening on ip address 192.168.1.x

So what changes will I have to make to my server and client application so that the client is able to find all the servers listening on port 2121?

like image 524
Tono Nam Avatar asked Sep 02 '11 17:09

Tono Nam


People also ask

How do I test a specific port on a network?

Press the Windows key + R, then type "cmd.exe" and click OK. Enter "telnet + IP address or hostname + port number" (e.g., telnet www.example.com 1723 or telnet 10.17. xxx. xxx 5000) to run the telnet command in Command Prompt and test the TCP port status.

Is a server listening on a port?

Listen Port - serves as an endpoint in an operating system for many types of communication. It is not a hardware device, but a logical construct that identifies a service or process. As an example, an HTTP server listens on port 80.

How do you check if a port is listening on a remote server?

One of the biggest perks of Telnet is with a simple command you can test whether a port is open. Issuing the Telnet command telnet [domainname or ip] [port] will allow you to test connectivity to a remote host on the given port.


2 Answers

The algorithm you proposed is the one you need. One problem is in the dynamic generation of the candidate IP addresses.

Normally, the possible IP address range is the one given by the subnet mask ( http://en.wikipedia.org/wiki/Subnetwork ). More exactly, the part of the IP that change is that part when in the subnet mask you have 0bits (always at the end of mask).

In your example:

  • if the mask is 255.255.255.0, then your possible ip address range is 192.168.0.*.
  • if the IP can also be 192.168.1.* then probably the mask should be 255.255.0.0
  • you can also have mask like 255.255.255.128 and the range would be 192.18.1.[1-126]. You can practically learn more using http://www.subnet-calculator.com/

The only other possibilities which cause your problem that I see to have these distinct ranges are:

  • you have more DHCP servers in your network, which is really bad as you will have "race conditions". The solution here is to fix your infrastructure by removing all but 1 DHCP server
  • you have manually set IP addresses (probably on laptops). The solution is to change to DHCP (if you need a specific IP that will always be assigned to a specific computer, use static DHCP)

Getting back to the problem of finding the problem of checking if "something" is listening on a specific port, the ICMP protocol is not the best here, as the majority of firewalls filter both the broadcast ICMP and single ICMP. If we are truly talking of a server, chances are you had to manually open the port you are looking for. Also, even if all computers respond, you still don't know if they host your wanted service.


The solution below involves computing the possible range of candidate IP addresses. After that you iterate through them to see if you can connect to your port.

In this implementation I test sequentially, which proves to be very slow as the timeout for connect is 30 seconds if the host is not on. For several hundred candidates, it doesn't sound too good. However, if the majority of host are available (even if they don't host your service), everything will go several times faster.

You can improve the program by either finding out how to decrease this timeout (I couldn't find out how in my allocated time) or to use a custom timeout as presented in How to configure socket connect timeout . You could also use multi-threading and adding the address that worked in a thread-safe collection and work with it from there.

Also, you could try pinging (ICMP) before, but you could miss valid servers.


    static void Main(string[] args)
    {

        Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        int wantedPort = 21;    //this is the port you want

        byte[] msg = Encoding.ASCII.GetBytes("type msg here");


        foreach (NetworkInterface netwIntrf in NetworkInterface.GetAllNetworkInterfaces())
        {

            Console.WriteLine("Interface name: " + netwIntrf.Name);

            Console.WriteLine("Inteface working: {0}", netwIntrf.OperationalStatus == OperationalStatus.Up);

            //if the current interface doesn't have an IP, skip it
            if (! (netwIntrf.GetIPProperties().GatewayAddresses.Count > 0))
            {
                break;
            }

            //Console.WriteLine("IP Address(es):");

            //get current IP Address(es)
            foreach (UnicastIPAddressInformation uniIpInfo in netwIntrf.GetIPProperties().UnicastAddresses)
            {
                //get the subnet mask and the IP address as bytes
                byte[] subnetMask = uniIpInfo.IPv4Mask.GetAddressBytes();
                byte[] ipAddr = uniIpInfo.Address.GetAddressBytes();

                // we reverse the byte-array if we are dealing with littl endian.
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(subnetMask);
                    Array.Reverse(ipAddr);
                }

                //we convert the subnet mask as uint (just for didactic purposes (to check everything is ok now and next - use thecalculator in programmer mode)
                uint maskAsInt = BitConverter.ToUInt32(subnetMask, 0);
                //Console.WriteLine("\t subnet={0}", Convert.ToString(maskAsInt, 2));

                //we convert the ip addres as uint (just for didactic purposes (to check everything is ok now and next - use thecalculator in programmer mode)
                uint ipAsInt = BitConverter.ToUInt32(ipAddr, 0);
                //Console.WriteLine("\t ip={0}", Convert.ToString(ipAsInt, 2));

                //we negate the subnet to determine the maximum number of host possible in this subnet
                uint validHostsEndingMax = ~BitConverter.ToUInt32(subnetMask, 0);
                //Console.WriteLine("\t !subnet={0}", Convert.ToString(validHostsEndingMax, 2));

                //we convert the start of the ip addres as uint (the part that is fixed wrt the subnet mask - from here we calculate each new address by incrementing with 1 and converting to byte[] afterwards 
                uint validHostsStart = BitConverter.ToUInt32(ipAddr, 0) & BitConverter.ToUInt32(subnetMask, 0);
                //Console.WriteLine("\t IP & subnet={0}", Convert.ToString(validHostsStart, 2));

                //we increment the startIp to the number of maximum valid hosts in this subnet and for each we check the intended port (refactoring needed)
                for (uint i = 1; i <= validHostsEndingMax; i++)
                {
                    uint host = validHostsStart + i;
                    //byte[] hostAsBytes = BitConverter.GetBytes(host);
                    byte[] hostBytes = BitConverter.GetBytes(host);
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(hostBytes);
                    }

                    //this is the candidate IP address in "readable format" 
                    String ipCandidate = Convert.ToString(hostBytes[0]) + "." + Convert.ToString(hostBytes[1]) + "." + Convert.ToString(hostBytes[2]) + "." + Convert.ToString(hostBytes[3]);
                    Console.WriteLine("Trying: " + ipCandidate);


                    try
                    {
                        //try to connect
                        sock.Connect(ipCandidate, wantedPort);
                        if (sock.Connected == true)  // if succesful => something is listening on this port
                        {
                            Console.WriteLine("\tIt worked at " + ipCandidate);
                            sock.Close();
                            sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        }
                        //else -. goes to exception
                     }
                    catch (SocketException ex)
                    { 
                        //TODO: if you want, do smth here
                        Console.WriteLine("\tDIDN'T work at " + ipCandidate);
                    }
                }
            }
            Console.ReadLine();
        }
        sock.Close();
    }
like image 53
TDRv2.1 Avatar answered Sep 24 '22 09:09

TDRv2.1


(sorry for my bad english) I am actually needing something similar to this and just found out about multicast. Here you can find an article and example. The sample app from the article worked fine on my lan. I do not know exactly how it works but maybe you can multicast something from the client and have the server(s) to respond with its IP? Or if that do not work, have the server multicasting his IP in a timed interval should do it. Sorry for the lack of informations, i just learned about this :)

like image 25
Leo Avatar answered Sep 21 '22 09:09

Leo