networking · intermediate · ~12 min · safe pentest lab
Probe one TCP port on localhost using the same pattern a sysadmin uses to check 'is my service up'.
You're writing a tiny diagnostic helper: given a port number, tell the caller whether something on your own machine is listening on 127.0.0.1:port. No remote hosts. No scanning. Just a yes/no for one port on this machine.
This is the defensive analog of a port scanner. Sysadmins write a one-line version of this every other week ("is my dev server still up?"). The platform's safety rule turns the design constraint into the API: the function takes no host parameter at all — it's structurally incapable of touching anyone else's machine.
Implement:
int is_port_open(int port);
Return values:
1 — a TCP listener is on 127.0.0.1:port (your connect() succeeded).0 — the port is refused (ECONNREFUSED; no listener).-1 — a real error (couldn't even create a socket).int is_port_open(int port);
A port number (an int).
An integer: 1, 0, or -1.
127.0.0.1 inside the function. There is no host parameter. This is a deliberate structural guarantee: the function cannot probe third-party hosts.| port | what's on it | returns |
|---|---|---|
| 8080 (server is up) | listener | 1 |
| 1 (almost certainly nothing) | nothing | 0 |
| -1 (invalid) | n/a | -1 (socket creation may fail; see implementation) |
ECONNREFUSED is the explicit "no listener" signal — return 0.-1.socket() + connect(). If connect succeeds, something's there. If it returns -1 with errno == ECONNREFUSED, nothing is.sockaddr_in with INADDR_LOOPBACK and htons(port). Call connect(). Save errno before closing the socket (close can clobber it).close() before returning.host parameter "for flexibility". The whole point of the design is that there isn't one.errno against ECONNREFUSED specifically — other errnos shouldn't return 0.After this exercise you can build the smallest possible "did my dev server start?" check in one helper. Combined with tcp-client-connect, you have a complete client-side diagnostic.
The hard-coded 127.0.0.1 is the structural guarantee that this function can only probe the local machine. This exercise is for defensive learning in a local lab only. Do not use any variant of this technique on systems you do not own or have explicit permission to test.
The simplest 'is it alive?' check. Hard-coded to loopback so it's structurally incapable of misuse.
One integer port number.
1 (open), 0 (closed/refused), or -1 (real error).
Hard-code 127.0.0.1. No host parameter. Close the fd before returning on every code path.
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int is_port_open(int port) {
/* TODO */
return -1;
}
Leaking the fd. Treating every -1 as 'closed' instead of distinguishing ECONNREFUSED from real errors. Adding a host parameter (defeats the safety design).
Port 1 / port 65535 boundaries. A port that is open AND immediately closes the connection. Errno being clobbered by close() — save it first.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.