如何修改C语言端口扫描代码以遍历整个子网
Hey there! Your idea to strip the last octet of the IP and loop from 1-254 is exactly the right approach. Let's walk through how to implement this step by step—since you're new to C, I'll break down each part clearly so you understand what's happening.
Key Concepts to Grasp
When you convert a dotted IP string (like 192.168.1.10) to a 32-bit integer with inet_addr, it's stored in network byte order (big-endian). To keep the first three octets (the subnet core) and vary the last one, we'll use a bitmask to "zero out" the last octet, then loop through values 1-254 to fill that spot.
Step 1: Fix the Unsafe gets() Function
First off, gets() is extremely risky because it doesn't check buffer bounds—let's swap it with fgets() to avoid crashes or security issues. We'll also clean up the newline character that fgets() automatically adds.
Step 2: Add Subnet Scanning Logic
We'll modify your code to:
- Parse the input IP into a network-order 32-bit integer
- Mask out the last octet to get the base subnet address
- Loop through 1-254 for the last octet, creating a new IP each time
- Scan port 445 on every new IP in the subnet
Modified Code with Detailed Comments
Here's your updated code with subnet scanning support, plus explanations for key changes:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <ctype.h> #include <errno.h> void portScan() { struct hostent *host; int err, sock; char hostname[100]; struct sockaddr_in sa; uint32_t base_ip; // Stores the subnet's base (first 3 octets) int last_octet; // Get subnet base IP (e.g., 192.168.1.1 or 192.168.1.0) printf("Enter subnet base IP (e.g., 192.168.1.1): "); fgets(hostname, sizeof(hostname), stdin); // Remove the newline character added by fgets hostname[strcspn(hostname, "\n")] = '\0'; // Initialize sockaddr_in structure to zero memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(445); // Target port is fixed to 445 // Convert input IP to network-order 32-bit integer base_ip = inet_addr(hostname); if (base_ip == INADDR_NONE) { fprintf(stderr, "Error: Invalid IP address entered\n"); return; } // Mask out the last octet (keep first 3 octets intact) // 0xFFFFFF00 clears the last 8 bits (the final octet) base_ip &= 0xFFFFFF00; printf("Starting subnet scan for port 445...\n"); // Loop through valid last octet values (1-254; skip 0 and 255) for (last_octet = 1; last_octet <= 254; last_octet++) { // Combine base subnet with current last octet // htonl converts last_octet to network order to match base_ip sa.sin_addr.s_addr = base_ip | htonl(last_octet); // Convert network-order IP back to dotted string for printing char current_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &sa.sin_addr, current_ip, INET_ADDRSTRLEN); // Create TCP socket sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("Socket creation failed"); continue; // Skip to next IP instead of exiting the program } // Attempt connection to port 445 err = connect(sock, (struct sockaddr*)&sa, sizeof(sa)); if (err < 0) { // Port is closed or host is unreachable (no need to print this) fflush(stdout); } else { printf("%s: Port 445 is open\n", current_ip); } close(sock); } printf("\nSubnet scan complete!\n"); fflush(stdout); } // Example main function to run the scanner int main() { portScan(); return 0; }
Key Changes Explained
fgets()instead ofgets(): Prevents buffer overflow by respecting the buffer size, andstrcspn()removes the unwanted newline character.- Base IP Masking:
base_ip &= 0xFFFFFF00clears the last 8 bits of the IP, leaving us with the subnet's core (e.g.,192.168.1.0if input was192.168.1.10). - Last Octet Loop: We skip 0 (network address) and 255 (broadcast address) and combine each valid value with the base IP using
htonl()to ensure proper network byte order. - Robust Error Handling: If socket creation fails, we skip to the next IP instead of exiting, making the scan more resilient.
- IP String Conversion:
inet_ntop()converts the raw network-order IP back to a human-readable string so we can clearly report which hosts have an open port.
Extra Tips for Improvement
- To support other subnet masks (like /16 instead of /24), adjust the bitmask—for example,
0xFFFF0000would keep the first two octets and vary the last two. - Add a small delay (using
sleep(1)) between scans to avoid triggering network security alerts. - For faster scanning, you could use threads to scan multiple IPs in parallel, but that's a more advanced topic—start with this sequential version first.
内容的提问来源于stack exchange,提问作者Henry F

