Credit for the idea goes to Steve Gibson of Gibson Research Corportion who created and maintains Shields Up!
A comment he made during his podcast (Security Now) in July 2022 that an IPv6 version of Shields Up! did not exist got me thinking: I could implement a port scanner myself for both IPv6 and IPv4.
I've listened to every episode of his podcast (800+) where he occasionally discusses how his port scanner works and between that and the documentation of Shields Up! at his web site I had a fairly good idea of some of the under-the-hood features that were necessary to make this work. Initially I used Node.js's built in TCP libraries but that began to cause problems so the code was eventually switched to raw sockets.
By the book TCP connoisseurs will note that a TCP port should only report open or closed. A stealth port is one that does not respond at all to a connection attempt. I again tip my hat to Steve Gibson for coining this term.
The concept was controversial. Some would argue that any system on the internet should properly reply to a TCP connection request at a port that is not listening with closed. However, by responding you are confirming a computer exists at this IP address and thus may make your computer the target of additional probes and attempts to break in.
Over time stealth has become much more accepted. Even the big name cloud providers all default all of the virtual servers that you spin-up in their environments to stealth and require that you explicitly list which ports will be accepting incoming connections.
Some of the most modern protocols have implemented an adaptive stealth methodology where the server will only respond if a properly formed packet for the listening protocol is received. Thus if someone is scanning for open ports, unless they are offering packets for the right protocol, your machine will still appear stealth. Wireguard is known to do this.
The standard scan will scan ports 0-1056. By definition, ports 1-1024 are reserved for use by the system to listen for incoming requests. Microsoft has been known to use ports just beyond this range as well. By scanning these ports you will find out if your compter is offering any of the common servers to the internet such as HTTP or HTTPS (web site), SMTP (email), file share, printer share, FTP (file transfer), and others. The scan will take just over a minute to complete.
This scan only tests ports which run common services such as HTTP, POP3 and others. Several ports tested will be beyond the port number 1024 as newer software has taken to claiming their own port number as a de-facto default. This list will evolve over time as new software is created or specific vulnerabilities are uncovered with specific port/software combinations.
IP addresses come in two flavors, the original 32-bit IPv4 address of which we have run out of the 4-some billion available. And 128-bit IPv6 addresses with a practically unlimited number of addresses available. Techniques such as NAT routing allow us to continue to use IPv4 while the world very slowly transitions to IPv6 even though it has been around for over 25 years. (It's said that IPv6 is the protocol of the future and always will be)
At the top of this page the scanner will announce if you've connected to the site over IPv4 or IPv6 and list your address. It will also check to see if you're connected via the opposite protocol and will offer you the option to switch to that ip address for the scan further down the page. This can also be used as a quick check to see if your network and devices are configured for both protocols.
You can also get to either scanner directly with these addresses:
These addresses can also be used for quick testing of your network and devices IPv4 and IPv6 connectivity because they will only connect over their respective protocols.
Sorry it can't be done.
This tool in intended for you to check the security of a network that you are a member of. As stated in the disclaimer above you must also have the authority to run a port scan against the ip address listed.
Thus the only IP addresses that can be scanned are the ones that you are currently connecting from.
The full 1056 port scan takes about 75 seconds to complete if the majority of your ports are stealth. This is by design. Ports are tested in groups of 32 at one time. Up to three packets are sent to each port. If an open or closed response is received no additional packets are sent. If no response is received up to two additional packets are sent after a short interval for a total of 3 packets. If none of these three packets receive a response the port is considered stealth. By testing 3 times and limiting to groups of 32 we guard against dropped packets due to network problems or overloading the target's router or server. Some additional per-client artificial limits are also implemented during heavy load to ensure this service remains fast and reliable for everyone using it.
This application runs as a set of microservices written in Node.js and is designed to be scalable.
The web site serves this introduction page and the test results. The test results are returned as a single html page, no javascript. A common and perfectly valid solution might be to return a page that contains javascript that will poll for test results at a regular interval. However the same can be accomplished by HTTP long-polling which means the connection stays open for a long time while we slowly send data to the client. The data sent is the individual tests results.
This method greatly simplifies what the web server needs to be able to do. And it provides the added benefit that you can test a headless system (such as a command-line-only server OS) with minimal pain. In linux you can run curl (or similar) pointed at the port scan url and watch the results returned to your screen one row at a time. The HTML has been deliberately kept simple to facilitate reading it in this way.
The long-polling response also does the following by removing the need for an API to respond to queries of test results
Node.js running Express was chosen as the web server because Node.js is designed to handle many connections with minimal resources, and holding open HTTP connections for several minutes per test means a lot of connections will be present at one time. Nginx is used in front of Node.js to terminate SSL, provide compression and to load balance to several backend servers.
Not unlike a distributor on a car built prior to the 1990's, the test distributor receives test requests from the web server and routes them to actual testers. It is implemented as an IPC server on TCP within the testing VPC.
When a test is requested, the web server produces a test request for each ip/port combination and attaches a unique test id. The request is sent to the distributor which passes the request to any number of connected testers in a round-robin balancing method.
When a test is complete the tester sends back a response that includes the port number, provided unique test id and the test result. These are then broadcast to all listening web servers.
The web server has the option, after a timeout, to consider ip/port combination in error separate from receiving a result from the distributor. This decoupling is intentional in case the distributor or other backend services encounter a problem during the test.
As implemented this piece cannot scale. But observation of the processes under load shows that it can handle a significant number of web servers and children connected to it with reasonable resource utilization. It is helped immensely by not having to hold the state of any test, the data just passes through. If necessary this could be replaced with a distributed pub/sub system such as Redis or Simple Queue Service.
The tester runs on a separate server from the web server by design. This ensures that connections made to your machine do not come from netbymatt.com, where your firewall recognizes that you have an ongoing connection. Some firewalls have been observed to respond differently to unsolicited packets received from an ip address that has other connections active. By using a different server we eliminate this problem.
In practice several testers run on one server. The number of testers that one server can support is limited more by memory than CPU because each test run requires significant memory to track the TCP connection progress. Each tester can run multiple tests simultaneously, currently set in the low hundreds.
Upon loading, each tester registers itself with the Test Distributor. This is done over TCP so if a tester unexpectedly goes offline it can be detected fairly quickly and removed from the Test Distributor pool. A tester that has gone offline is the typical cause for an intermittent port marked as "error" although after tuning the server sizes and tester counts this is now rare.
The tester receives a test from the Test Distributor and puts it in a queue waiting for one of its hundreds of available testers in its pool to become free. When the tester becomes free it receives the test request and runs the test on the ip address and port combination specified. On a stealth port, three connection attempts are made over the course of 2 seconds. Once the state of the port has been determined (open, closed, stealth) the test result is sent back to the Test Distributor.
Raw sockets are used to send a TCP SYN packet to the ip address being tested. This is deliberate. If Node.js's built in TCP methods were used and an open port is found a complete connection would be made. By using raw sockets we have control over if any response is sent to after receiving a SYN-ACK. In practice, a reset is sent immediately upon receiving a SYN-ACK as the SYN-ACK itself is confirmation that the port is open and we don't need to pursue the connection any further.
A wrapper around libpcap is used to receive all packets that are sent to the tester. The wrapper also parses received packets which are then checked against a list of outstanding tests and reported back to the individual tester if a SYN-ACK was received.
This process scales in three ways. Above, several testers can run on one server and each tester has a pool of several hundred tests that can be run simultaneously. Once one server's resources have been exhausted another server can be spun-up in the same configuration doubling the test capacity.
Several things have been engineered into this tester to provide as much privacy as possible.
Your IP address is never logged. It is read back to you on the test pages as a convenience but not logged by the web server. When running tests your IP address is passed to the Test Distributor and the Tester out of necessity to run the test.
All uses of logging in all three microservices have intentionally been designed to not log IP addresses nor port numbers when logging to internal access and error logs.
In order to monitor the health of this service and assess server loads the following items are counted as single events with no additional data attached such as IP addresses or port numbers.
Google Analytics is used on this page only to provide data on the number of visitors to this site. Google Analytics Privacy Policy