A Port Scanner in C

The following port scanner C code checks approximately 65535 ports in about 15 seconds on-network.

#include <stdio.h> #include <stdlib.h> #include <netinet/in.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <netdb.h> #include <sys/types.h> #include <sys/time.h> #include <sys/ioctl.h> #include <sys/wait.h>

#define MAX_PORTS 65535 #define MAX_SOCKETS 1023

// gcc -o portscanner portscanner.c

int scan_port(const char* host, int port) { struct sockaddr_in server; int sock;

sock = socket(AF\_INET, SOCK\_STREAM, 0);
if (sock == -1) {
    perror("socket");
    return -1;
}

server.sin\_addr.s\_addr = inet\_addr(host);
server.sin\_family = AF\_INET;
server.sin\_port = htons(port);

int flags = fcntl(sock, F\_GETFL, 0);
fcntl(sock, F\_SETFL, flags | O\_NONBLOCK);

if (connect(sock, (struct sockaddr \*)&server, sizeof(server)) == -1) {
    if (errno != EINPROGRESS) {
        perror("connect");
        return -1;
    }
}

fd\_set fdset;
struct timeval tv;

FD\_ZERO(&fdset);
FD\_SET(sock, &fdset);

tv.tv\_sec = 0;
tv.tv\_usec = 200000;  // Timeout of 200ms

int select\_ret = select(sock + 1, NULL, &fdset, NULL, &tv);

if (select\_ret == -1) {
    perror("select");
    return -1;
}
else if (select\_ret == 0) {
    close(sock);
    return 0;
}

// Connection successful, port is open
close(sock);
return 1;

}

void scan_ports(const char* host, int start_port, int end_port) { int num_sockets = 0; int port;

for (port = start\_port; port <= end\_port; port++) {
    pid\_t pid = fork();
    if (pid == -1) {
        perror("fork");
        exit(EXIT\_FAILURE);
    } else if (pid == 0) {
        // Child process
        int result = scan\_port(host, port);
        if (result == 1) {
            printf("Port %d is open\\n", port);
        }
        exit(EXIT\_SUCCESS);
    } else {
        // Parent process
        num\_sockets++;
        if (num\_sockets >= MAX\_SOCKETS) {
            wait(NULL);
            num\_sockets--;
        }
    }
}

}

int main(int argc, char* argv[]) { if (argc < 3 || argc > 4) { printf(“Usage: %s <port/start_port> [end_port]\n”, argv[0]); return 1; }

const char\* host = argv\[1\];
int start\_port = atoi(argv\[2\]);
int end\_port;

if (argc == 4) {
    end\_port = atoi(argv\[3\]);
    if (start\_port < 1 || start\_port > MAX\_PORTS || end\_port < 1 || end\_port > MAX\_PORTS || start\_port > end\_port) {
        printf("Invalid port range.\\n");
        return 1;
    }
} else {
    end\_port = start\_port;
    if (start\_port < 1 || start\_port > MAX\_PORTS) {
        printf("Invalid port.\\n");
        return 1;
    }
}

printf("Scanning ports %d to %d on host %s...\\n", start\_port, end\_port, host);
scan\_ports(host, start\_port, end\_port);
return 0;

}

Here is a Windows version; it is much slower.

// CFLAGS="-static-libgcc -static-libstdc++ -03" // i686-w64-mingw32-gcc -o portscanner.exe portscanner_win32.c -lws2_32

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <winsock2.h> #include <ws2tcpip.h> #include <process.h>

#pragma comment(lib, “ws2_32.lib”)

#define MAX_PORTS 65535

typedef struct { const char* host; int start_port; int end_port; } ScanParams;

int scan_port(const char* host, int port) { WSADATA wsaData; SOCKET sock; struct sockaddr_in server;

if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
    perror("WSAStartup");
    return -1;
}

sock = socket(AF\_INET, SOCK\_STREAM, 0);
if (sock == INVALID\_SOCKET) {
    perror("socket");
    WSACleanup();
    return -1;
}

server.sin\_addr.s\_addr = inet\_addr(host);
server.sin\_family = AF\_INET;
server.sin\_port = htons(port);

u\_long nonblocking = 1;
if (ioctlsocket(sock, FIONBIO, &nonblocking) != 0) {
    perror("ioctlsocket");
    closesocket(sock);
    WSACleanup();
    return -1;
}

if (connect(sock, (struct sockaddr\*)&server, sizeof(server)) == SOCKET\_ERROR) {
    int error = WSAGetLastError();
    if (error != WSAEWOULDBLOCK) {
        perror("connect");
        closesocket(sock);
        WSACleanup();
        return -1;
    }
}

fd\_set fdset;
struct timeval tv;

FD\_ZERO(&fdset);
FD\_SET(sock, &fdset);

tv.tv\_sec = 0;
tv.tv\_usec = 200000;  // Timeout of 200ms

int select\_ret = select(0, NULL, &fdset, NULL, &tv);

if (select\_ret == SOCKET\_ERROR) {
    perror("select");
    closesocket(sock);
    WSACleanup();
    return -1;
} else if (select\_ret == 0) {
    closesocket(sock);
    WSACleanup();
    return 0;
}

// Connection successful, port is open
closesocket(sock);
WSACleanup();
return 1;

}

unsigned int __stdcall scan_ports_thread(void* params) { ScanParams* scanParams = (ScanParams*)params; const char* host = scanParams->host; int start_port = scanParams->start_port; int end_port = scanParams->end_port; int port;

for (port = start\_port; port <= end\_port; port++) {
    int result = scan\_port(host, port);
    if (result == 1) {
        printf("Port %d is open\\n", port);
    }
}

\_endthreadex(0);
return 0;

}

void scan_ports(const char* host, int start_port, int end_port, int num_threads) { int ports_per_thread = (end_port - start_port + 1) / num_threads; int remaining_ports = (end_port - start_port + 1) % num_threads; int thread; HANDLE* scanThreads = malloc(num_threads * sizeof(HANDLE)); ScanParams* scanParams = malloc(num_threads * sizeof(ScanParams));

for (thread = 0; thread < num\_threads; thread++) {
    scanParams\[thread\].host = host;
    scanParams\[thread\].start\_port = start\_port + thread \* ports\_per\_thread;
    scanParams\[thread\].end\_port = scanParams\[thread\].start\_port + ports\_per\_thread - 1;

    if (thread == num\_threads - 1) {
        // Assign remaining ports to the last thread
        scanParams\[thread\].end\_port += remaining\_ports;
    }

    scanThreads\[thread\] = (HANDLE)\_beginthreadex(NULL, 0, scan\_ports\_thread, &scanParams\[thread\], 0, NULL);
}

// Wait for all threads to finish
WaitForMultipleObjects(num\_threads, scanThreads, TRUE, INFINITE);

free(scanThreads);
free(scanParams);

}

int main(int argc, char* argv[]) { if (argc < 3 || argc > 5) { printf(“Usage: %s <port/start_port> [end_port] [num_threads]\n”, argv[0]); return 1; }

const char\* host = argv\[1\];
int start\_port = atoi(argv\[2\]);
int end\_port;
int num\_threads = 25;

if (argc >= 4) {
    end\_port = atoi(argv\[3\]);
    if (argc == 5) {
        num\_threads = atoi(argv\[4\]);
    }
} else {
    end\_port = start\_port;
}

if (start\_port < 1 || start\_port > MAX\_PORTS || end\_port < 1 || end\_port > MAX\_PORTS || start\_port > end\_port) {
    printf("Invalid port range.\\n");
    return 1;
}

printf("Scanning ports %d to %d on host %s using %d thread(s)...\\n", start\_port, end\_port, host, num\_threads);
scan\_ports(host, start\_port, end\_port, num\_threads);
return 0;

}

Published At