Python › Module 2 › Lesson 3
Port Scanner Script
Walk through a beginner port scanner design: loops, sockets, and ethical limits
Opening
A teaching scanner is a for-loop with a conscience — the host string is the control, not an afterthought.
You already know one TCP connect: host, port, timeout, connect_ex, close. A beginner port scanner is that call inside a loop over a small list of ports, recording OPEN versus closed_or_filtered. Production scanners add concurrency, rate limits, service detection, and legal paperwork. You do not need those to understand the idea. You do need to understand that unauthorized scanning is illegal in many places and looks like an attack in logs everywhere. This lesson is DESIGN. You will walk the algorithm on paper and in a short skeleton aimed at 127.0.0.1. Scope is the control: if HOST is loopback, you are learning; if HOST is the café /24, you are attacking. Banner grabbing (reading a few bytes after connect) is optional and localhost-only. Next lesson is the lab: copy-paste Python, hardcoded 127.0.0.1, tiny port list, notes in $HOME/cyberlium-lab. Do not skip ahead to nmap. Do not “try it on the dorm.”
1. The algorithm is three parts: target, port list, connect test — then record
Write it in words before code. (1) Target: a single host constant, "127.0.0.1". (2) Port list: a handful of well-known numbers you already recognize — 22, 80, 443, 8000, 3306 — not range(1, 65536). (3) For each port: create SOCK_STREAM, settimeout(0.5 or 1.0), connect_ex((host, port)), if 0 then OPEN else closed_or_filtered, close socket, print and/or append a line. That is a connect scanner from your vantage point. It is not a SYN stealth scan, not UDP, not nmap -A, not a vulnerability exploit. Open means the TCP handshake completed. Closed/filtered means it did not, in the time you waited. Firewalls can make live services look closed. Loopback still teaches the loop without touching anyone else.
Why a list instead of 1–65535 on day one: time, noise, and ethics. Even on localhost, a full 65k connect scan is slow with a 1-second timeout (worst case: hours) and teaches nothing extra about the loop. On any other host it is a loud event in IDS. Small lists keep the lesson about control flow. You can extend the list later on YOUR VM after the lab — still not across a /24 you do not own.
2. Scope is the control: the same loop is a lesson or a crime depending on HOST
Authorization does not live in Python. connect_ex does not check a get-out-of-jail card. Skill does not create consent. Scanning random internet hosts, café Wi-Fi clients, an ISP’s equipment, a school subnet, or a neighbor’s router without written permission is unauthorized access / abuse of the network, regardless of “I am a student” or “I did not use nmap.” A TCP connect scan is still a scan. Keep the teaching tool on YOUR loopback. A lab VM you installed, whose IP you typed because you own the hypervisor, can be in scope later — still not the café. Print the host at the start of every run so a mistake is obvious before the loop. Hardcode the host so a mistake is harder.
Logging is part of scope. If you do not print HOST, you will not notice you pointed the script at yesterday’s cloud IP. If you log to a world-writable file, someone else on a shared PC reads your output. Notes go to $HOME/cyberlium-lab with chmod 600. They contain port numbers and OPEN/closed — not passwords, not other people’s IPs, not a trophy screenshot of a bank. The next lab will require that file path on purpose so evidence practice matches Topic 2/6 habits.
3. Open vs closed vs filtered — clues from here, not absolute truth
OPEN: connect_ex returned 0. Something accepted TCP. On 127.0.0.1 that something is a process on YOUR machine (ss -tuln / netstat can confirm). closed: typical connection refused — no listener, stack sent RST. filtered / timeout: the timeout fired; a drop or a slow path, not a clean RST. Beginners collapse the last two into closed_or_filtered, which is honest. Do not upgrade a timeout into “the host is down” or “the host is hiding NSA secrets.” Do not treat OPEN on localhost:8000 as a finding you must exploit. If you started http.server, OPEN is the expected reward for the next lab, not a vulnerability write-up.
False pictures: a listener bound to 127.0.0.1:8080 is OPEN from this scanner on loopback and invisible from another laptop. A listener on 0.0.0.0:8000 is reachable from more paths — still only your machine if you are in NAT. Scanning a public IP to “see the difference” is how labs go off the rails. Stay on 127.0.0.1 until the written lab says you may use a VM you control. This design lesson does not require a second host at all.
4. Banner grabbing lite is optional, localhost only — a few recv bytes, not a brute
After a successful connect, some services send a greeting (SSH version line, SMTP banner, HTTP if you send a request). Reading a small recv() on 127.0.0.1 after you connected to a listener YOU started is optional literacy. It is not required for the design. It is not permission to pull banners from the internet, not a version-to-CVE pipeline, not an nmap -sV clone. Cap the recv (for example 64–256 bytes), keep the timeout, close the socket. Do not send crafted protocol probes to strangers. Do not brute login on an OPEN 22. OPEN is “a door existed,” not “walk in.”
If you skip banners entirely, you still have a complete beginner scanner: loop, connect_ex, record. That is what the lab implements. Banner code that takes HOST from argv will be the first thing someone aims at a school jumphost. Leave HOST hardcoded. Leave banners off unless you are talking to your own http.server.
5. Wrong vs right: nmap the café vs a loopback design with a tiny list
Worked failure — same for-loop, opposite blast radius. Unauthorized scanning is illegal; this is a learning tool for YOUR loopback.
Wrong
Point the skeleton at 192.168.1.0/24, the café gateway, an ISP resolver, or a .edu lab you do not own. Use nmap -p- because the Python loop is “too slow.” Banner-grab production SSH. Treat OPEN as a password prompt. Skip timeouts. Scan 1–65535 on a roommate’s laptop. Call it homework. Courts and school AUP do not grade it as homework. This course gives no stealth-scan, masscan, or exploit-after-open steps.
Right
Design: HOST constant 127.0.0.1, PORTS = [22, 80, 443, 8000, 3306], TIMEOUT ~0.5–1s, connect_ex, record OPEN/closed, print the host first. Optional banner recv only on a listener you started. Next lab: run it, write $HOME/cyberlium-lab/localhost-scan.txt, chmod 600, optionally start python -m http.server 8000 on YOUR machine to see one OPEN. No LAN, no café, no school, no random internet hosts.
6. Practical: write the skeleton with HOST locked — do not fire it at a LAN
Study the conceptual flow, then the tiny Python skeleton. You may run the skeleton on 127.0.0.1 now; you will expand it in the next lab. If every port is closed, that is a valid design check — many laptops listen on nothing in that list until you start http.server. Do not “fix” empty OPEN by changing HOST. Do not install nmap to compare. Save a design note if you want; chmod 600. The mission is that you can explain the loop and the legal line before you copy a longer script.
Command guide
Design skeleton — 127.0.0.1, tiny list, timeout, record OPEN
DESIGN / teaching skeleton. HOST is a constant. Not a /24 scanner. Not nmap. Unauthorized scanning (café, ISP, school, random internet) is illegal.
Command — copy this
HOST = "127.0.0.1" # lock this; next lab keeps it hardcoded PORTS = [22, 80, 443, 8000, 3306] # small list — not range(1, 65536) TIMEOUT = 0.5
for each port in PORTS: socket AF_INET + SOCK_STREAM settimeout(TIMEOUT)
Optional command
err = connect_ex((HOST, port))
if err == 0: record OPEN else: record closed_or_filtered close socket print HOST first so a mistake is obvious
Command — copy this
print(f"DESIGN CHECK target={HOST} ports={PORTS} timeout={TIMEOUT}")
print("Next lab: implement this on localhost only; write localhost-scan.txt mode 600")Optional later, LOCALHOST ONLY: after OPEN, sock.recv(128) from a server YOU started NEVER: banner grab or connect_ex against café / ISP / school / random hosts NEVER: nmap, masscan, SYN stealth, login brute on OPEN 22
Mission: explain the loop before you widen it
1) Write the three parts of a beginner connect scanner (target, small port list, connect_ex + record). 2) Explain why HOST is the control, why unauthorized scanning is illegal, and why 1–65535 on a LAN is not a lesson. 3) State open vs closed_or_filtered from your vantage point, and that banners are optional on localhost only. You may run the skeleton against 127.0.0.1; do not change the host. Optional notes under $HOME/cyberlium-lab, chmod 600. Next lesson builds the full script.
Stuck? Ask Cyberlium AI Mentor
If “a scanner is only real if it hits a /24” still feels true, ask for a hint — not a target list. Try: "Hint only: why is a five-port connect_ex loop on 127.0.0.1 a complete beginner scanner, what OPEN actually proves, and why is nmap against café Wi-Fi out of scope?" You still keep HOST locked. No stealth scans, no school subnets.
You now can design a connect scanner as a loop with a timeout and a tiny port list, and you know the host string is the ethics control. OPEN is a vantage-point clue. Unauthorized scanning is illegal; this tool is for YOUR loopback. Banner grabs stay optional and local. Next — Lab — Build a Port Scanner — copy-paste Python, HOST hardcoded to 127.0.0.1, results in localhost-scan.txt mode 600, optional http.server on port 8000 on YOUR machine.
Knowledge Check
APPLY: A classmate says the design is incomplete until it scans the campus 10.0.0.0/8 with nmap -p-. What is a beginner connect scanner, and what is the legal line?
Multiple choice
Knowledge Check
APPLY: True or False: connect_ex == 0 on 127.0.0.1:8000 means the port is safe to brute, and a timeout means you should move HOST to the café gateway to get a cleaner RST.
True or False
Knowledge Check
APPLY: Which defaults belong in the teaching design?
Multiple choice