November 26th, 2008
Building a simple portscanner in C# - 0

In the dark ages before the Internet there was “war-dialing”: randomly calling telephone numbers in the hope that on the other side a computer modem would pick up. War Dialing was glamorized by the movie “Wargames” but portscanning is just like that: you too can help the world narrowly avoid nuclear Armageddon. This article shows how you can build a simple Portscanner in C#.
And with simple we mean simple, this is no NMAP. But given an IP address or domain name address it will slowly scan each available port of the target computer to see if its open.
Port scanning www.hinet.net (203.66.88.89) Scanning port 0 : closed Scanning port 1 : closed Scanning port 2 : closed Scanning port 3 : closed .... Scanning port 7 :
Scanning is done by connect scanning the target computer. The program tries to build a connection to the IP address / port of the target. If it succeeds the port is open.
There is a gotcha here : The .NET implementation of TCPClient.Close() function does not actually close the connection properly. So we need to do the additional steps of obtaining the stream representing the connection and closing this as well before calling TCPClient.Close.
When starting the program you need to pass a domain name or IP address on the command line. We use a little regular expression magic in the IsIpAddress() method to determine if we were passed a valid IP address.
If a domain name was passed the LookupDNSName() method uses DNS to locate the matching IP address. Since more than one IP address can be represent a single domain name, the first one returned is selected.
The actual scanning is done by ScanPort(), a successful connection makes it return true.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;
namespace PortScanner
{
class Program
{
// IsIpAddress
//
// The following routine returns true if a given string is a valid IP address
static bool IsIpAddress(string Address)
{
// The following pattern matches an IP address
Regex IpMatch = new Regex(@"\b(?:\d{1,3}\.){3}\d{1,3}\b");
return IpMatch.IsMatch(Address);
}
// LookupDNSName
//
//
static bool LookupDNSName(string ScanAddress, out IPAddress ScanIPAddress)
{
ScanIPAddress = null;
IPHostEntry NameToIpAddress;
try
{
// Lookup the address we are going to scan
NameToIpAddress = Dns.GetHostEntry(ScanAddress);
}
catch(SocketException)
{
// Thrown when we are unable to lookup the name
return false;
}
// Pick the first address in the list , there should be at least 1
if (NameToIpAddress.AddressList.Length > 0)
{
ScanIPAddress = NameToIpAddress.AddressList[0];
return true;
}
return false;
}
static bool ScanPort(IPAddress Address, int Port)
{
TcpClient Client = new TcpClient();
try
{
// Attempt to connect to the given address + port
Client.Connect(Address, Port);
// This may seem like an avoidable step -- but TcpClient.Close does not
// actually close the underlying connection
// http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B821625
NetworkStream ClientStream = Client.GetStream();
ClientStream.Close();
// Free the TCPClient resource
Client.Close();
}
catch(SocketException)
{
// Assume that a socket exception means the connection failed
// Client.Connect returns a void (so provides no insights into
// what it was doing)
return false;
}
return true;
}
static void Main(string[] args)
{
String ScanAddress;
IPAddress ScanIPAddress;
try
{
// Try to read the scan address from the command line, or default to localhost
if (args.Length != 0)
ScanAddress = args[0];
else
ScanAddress = "127.0.0.1";
// Both a hostname or an IP address are fine
if (IsIpAddress(ScanAddress))
{
ScanIPAddress = IPAddress.Parse(ScanAddress);
}
else
if (!LookupDNSName(ScanAddress,out ScanIPAddress))
{
Console.WriteLine("Error looking up {0}",ScanAddress);
return;
}
// Report what we are going to do
Console.WriteLine("Port scanning {0} ({1})", ScanAddress, ScanIPAddress.ToString());
// Scan all the possible posts
for (int Port = IPEndPoint.MinPort; Port < IPEndPoint.MaxPort; Port++)
{
Console.Write("Scanning port {0} : ", Port);
if (ScanPort(ScanIPAddress, Port))
Console.WriteLine("OPEN");
else
Console.WriteLine("closed");
}
// Close Up
Console.WriteLine("Finished scanning all ports");
}
catch (Exception e)
{
Console.WriteLine("Exception caught!");
Console.WriteLine("Source : " + e.Source);
Console.WriteLine("Message : " + e.Message);
}
}
}
}
As there are some 2^16 addresses (IPEndPoint.MinPort = 0 / IPEndPoint.MaxPort = 65536) this program will take its quite a bit of time to scan a whole machine. Also, if a port is closed (or hidden by a firewall) the TCPClient will need to wait for a timeout before being able to report this.
One possible solution to this would be to scan multiple ports simultaneously with a set of ThreadPool workers as most of the time the main thread is waiting for the TCP stack.
Image credit: makelessnoise
Tags: Learn C#, portscanner, tcpclient









Except where otherwise noted, content on this site is