Building a Port Scanner Tool in C++

Introduction

In today’s digital landscape, cybersecurity has become paramount for individuals and organizations alike. Ensuring the security of networks, identifying potential threats, and maintaining system integrity require various tools and techniques. Among these tools, port scanners play a critical role in identifying open ports on a network. Open ports can serve as gateways for malicious users to infiltrate systems. Therefore, system administrators and security professionals often use a C++ Port Scanner Tool to assess their networks and identify vulnerabilities.

Port scanners work by attempting to connect to specific IP addresses or hosts to determine which ports are open. This process is typically carried out over the TCP/IP protocol and is essential for evaluating the security of a system. C++, known for its high performance and flexibility, is an excellent choice for developing such tools. In this article, we will create a simple port scanner tool using C++. We will develop an application that takes user input for a target IP address and a range of ports, then identifies which of those ports are open.

Learning Objectives

By the end of this article, readers should be able to:

  1. Understand the Basics of Port Scanners: Grasp how port scanners operate and why they are important.
  2. Learn C++ Socket Programming: Gain knowledge about socket programming in C++ and apply it in practice.
  3. Implement Dynamic Input Handling: Develop a dynamic port scanner tool that takes user input.
  4. Detect Open Ports: Create an application that identifies open ports on a specified IP address.
  5. Manage Errors Effectively: Implement error handling within the application to write more robust code.
  6. Develop Cybersecurity Awareness: Understand the importance of ethical practices in network scanning.

The primary function of our port scanner will be to attempt to connect to each port within a specified range on a given target IP address. If the connection is successful, the port is considered open.

Project Goals

The goal of this project is to create an application that accepts a target IP address and a range of ports from the user, then identifies which ports are open within that range. We will implement a user-friendly interface for this process and display the results on the screen. Additionally, we will enhance user feedback through effective error management.

By developing our port scanner, we will achieve several advantages:

  • Security Analysis: System administrators can identify open ports on their networks and pinpoint potential security vulnerabilities.
  • Efficiency: The ability to automatically scan multiple ports saves time compared to manual checks.
  • Educational Tool: This project serves as a practical educational tool for those looking to learn socket programming in C++.

Let’s Write the Code

Below is the code for a simple port scanner tool written in C++:

1. Including Necessary Libraries

In this section, we include several header files that provide the necessary functions and definitions for our port scanner:

  • #include <iostream>: This library is used for input and output operations, allowing us to use std::cout and std::cerr.,
  • #include <cstdlib>: This library provides functions for performing general functions such as converting strings to integers (std::atoi).
  • #include <cstring>: This library is used for C-style string manipulation functions.
  • #include <cerrno>: This library defines macros for reporting and retrieving error conditions through error codes.
  • #include <netinet/in.h>: This library contains definitions for internet operations, including data structures used in network programming.
  • #include <arpa/inet.h>: This library provides functions for converting IP addresses from text to binary format.
  • #include <sys/socket.h>: This library contains definitions for socket programming, including the creation and management of sockets.
  • #include <unistd.h>: This library provides access to the POSIX operating system API, including functions to close sockets.
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
2. Main Function and Argument Checking

The main function is where the execution of the program begins. Here, we also check if the user has provided the correct number of command-line arguments:

  • argc: This parameter counts how many arguments are passed to the program (including the program name).
  • argv: This is an array of C-style strings representing each argument.

If the number of arguments is not equal to 4 (the program name plus three additional arguments), an error message is printed, and the program exits with a return code of 1.

int main(int argc, char* argv[]) {
    // Check for correct number of arguments
    if (argc != 4) {
        std::cerr << "Usage: " << argv[0] << " <target-ip> <start-port> <end-port>" << std::endl;
        return 1;
    }
3. Storing User Input

Here, we store the user input into appropriate variables:

  • const char* target_ip: This variable holds the target IP address as a string.
  • int start_port: This variable converts the second command-line argument (the starting port) from a string to an integer using std::atoi.
  • int end_port: Similarly, this variable converts the third command-line argument (the ending port) from a string to an integer.
    const char* target_ip = argv[1];
    int start_port = std::atoi(argv[2]);
    int end_port = std::atoi(argv[3]);
4. Looping Through Port Range and Socket Creation

This section initiates a loop that iterates through each port in the specified range:

  • For each port, a new socket is created using socket(AF_INET, SOCK_STREAM, 0).
  • If socket creation fails (returns -1), an error message is printed using strerror(errno) to display the corresponding error message. The program then exits with a return code of 1.
    // Loop through the specified port range
    for (int port = start_port; port <= end_port; ++port) {
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1) {
            std::cerr << "Could not create socket: " << strerror(errno) << std::endl;
            return 1;
        }
5. Setting Up Server Address Structure

Here, we define a sockaddr_in structure to specify the address of the server we want to connect to:

  • server_address.sin_family = AF_INET;: Specifies that we are using IPv4 addresses.
  • server_address.sin_port = htons(port);: Converts the port number from host byte order to network byte order using htons, ensuring proper byte representation across different architectures.
        sockaddr_in server_address;
        server_address.sin_family = AF_INET;
        server_address.sin_port = htons(port);
6. IP Address Conversion

In this section, we convert the target IP address from its textual representation to a binary format that can be used in network functions:

        // Convert IP address from text to binary form
        if (inet_pton(AF_INET, target_ip, &server_address.sin_addr) <= 0) {
            std::cerr << "Invalid IP address" << std::endl;
            close(sock);
            return 1;
        }
7. Connecting to Ports

Here, we attempt to connect to each specified port:

  • The connect function tries to establish a connection with the server at the specified address and port.
  • If successful (returns 0), it indicates that the port is open, and a message is printed to inform the user.
        // Attempt to connect to the port
        if (connect(sock, (struct sockaddr*)&server_address, sizeof(server_address)) == 0) {
            std::cout << "Port " << port << " is open" << std::endl;
        }
8. Closing Sockets

After checking each port, we close the socket using close(sock) to free up system resources.

        close(sock); // Close the socket after checking
    }
9. Program Termination

Finally, we return 0 from the main function, indicating that the program has executed successfully without errors.

    return 0;
}

Port scanning in C++
C++ network security tool
Open port detection using C++
Socket programming in C++
Network vulnerability assessment tool

Conclusion

In this article, we developed a simple port scanner tool using C++. This application takes user input for a target IP address and a range of ports and identifies which ports are open within that range. This tool can be beneficial for network security assessment and management. Port scanners like this one can enhance network security while also revealing potential vulnerabilities. However, it is crucial always to adhere to ethical guidelines; unauthorized scanning of other systems can lead to legal issues.

In conclusion, projects like this allow you to improve your socket programming skills in C++ while also gaining experience in building more complex network applications. Anyone interested in cybersecurity should consider practical projects like this one as valuable learning opportunities.

You May Be Interested In:

7 thoughts on “Building a Port Scanner Tool in C++”

    • Port scanners help identify open ports, which can indicate potential vulnerabilities in a network. They allow system administrators to assess security, monitor unauthorized access, and ensure that only necessary services are exposed.

      Reply
    • You can use C++11 threads by including and creating a thread for each port scan operation:

      #include 
      
      void scanPort(const char* target_ip, int port) {
          // Socket creation and connection logic here...
      }
      
      for (int port = start_port; port <= end_port; ++port) {
          std::thread(scanPort, target_ip, port).detach(); // Detach thread for concurrent execution
      }
      
      Reply
    • Yes, Here’s an example function that logs open ports:

      #include 
      
      void logOpenPort(int port) {
          std::ofstream logFile("open_ports.txt", std::ios::app);
          if (logFile.is_open()) {
              logFile << "Port " << port << " is open" << std::endl;
              logFile.close();
          }
      }
      
      Reply

Leave a Reply