1

I'm writing a port scanner with the intent to loop through an entire subnet to see if port 445 is open on any of the hosts as a way to learn C programming. The way that this program is currently setup, one needs to manually enter in a single IP address, and the scanner fires off. It is working perfectly (finally).

The current issue I'm facing: I'm not sure how to approach making this program scan an entire subnet, rather than just a single host. After researching this question, I believe the best route to pursue would be stripping off the last octet of the IP address, and having it loop from 1-254. However, I'm not entirely sure how to begin approaching this issue. This is my current code (heavily commented for clarification):

...
void portScan() {

struct hostent *host;
    int err, i , sock ,start , end;
    char hostname[100];
    struct sockaddr_in sa;

    //Get the hostname to scan
    printf("Enter hostname or IP to scan: ");
    gets(hostname);

    //Get start port number
    start = 445;

    //Get end port number
    end = 445;

    //Initialise the sockaddr_in structure
    strncpy((char*)&sa , "" , sizeof sa);
    sa.sin_family = AF_INET;

    //direct ip address, use it
    if(isdigit(hostname[0])) {
        sa.sin_addr.s_addr = inet_addr(hostname);
    }

    //Start the port scan loop
    printf("Starting the portscan loop : \n");

    for( i = start ; i <= end ; i++) {
        //Fill in the port number
        sa.sin_port = htons(i);

        //Create a socket of type internet
        sock = socket(AF_INET , SOCK_STREAM , 0);

        //Check whether socket was created or not
        if(sock < 0) {
            perror("\nSocket");
            exit(1);
        }
        //Connect using that socket and sockaddr structure
        err = connect(sock , (struct sockaddr*)&sa , sizeof sa);

        //not connected
        if(err < 0) {
            //printf("%s %-5d %s\r" , hostname , i, strerror(errno));
            fflush(stdout);
        }
        //connected
        else {
            printf("%-5d open\n",  i);
        }
        close(sock);
    }

    printf("\r");
    fflush(stdout);
}

TL;DR: I'm not sure how to approach modifying this code to strip the last octet of the IP address, and loop through the subnet by replacing the last octet with a 1 - 254. Any feedback, ideas or help is highly appreciated! Still highly junior in the C world.

Henry F
  • 4,960
  • 11
  • 55
  • 98
  • 1
    `strncpy` from a null string makes no sense. Did you mean [`memset` or `=0`](https://stackoverflow.com/questions/20651531/how-to-initialize-variables-for-struct-sockaddr-in)? – Davis Herring Jan 07 '18 at 07:04
  • @DavisHerring Ah interesting, thank you for the feedback and catching that! Looking into the details of that right now. – Henry F Jan 07 '18 at 07:06
  • You are asking the question, so what was too long that you didn't read (`TL;DR:`)?? – David C. Rankin Jan 07 '18 at 09:28

2 Answers2

5

The subnets are not just "the last byte". Instead in CIDR there is a prefix length/subnet mask. You just need one address from the subnet, and the subnet mask as unsigned integers, but in the host byte order, (you need to use ntohl on the return value of inet_addr and htonl to convert the integer again into an address that can be stored into s_addr).

  • You & the host address with the subnet mask to get the network address.

  • You | the network address with the inverse of the mask to get the broadcast address.

  • The host addresses within the network are all the numbers that are in between these 2, so you can write a for loop that starts from network_address + 1 and ends with broadcast_address - 1.

So, if your host address is 10.24.41.169 and prefix length is 23, the address in hex is 0x0A1829A9. The netmask has 23 first bits set to 1 and rest to 0, i.e. 0b11111111111111111111111000000000, i.e. 0xFFFFFE00 in hex.

uint32_t host = 0x0A1829A9;
uint32_t netmask = 0xFFFFFE00;

Now the network address is host & netmask:

uint32_t network_address = host & netmask;

And broadcast address is network_address | ~netmask; or host_address | ~netmask:

uint32_t network_address = host_address | ~netmask;

The addresses within the subnet can be generated by a rather brainless for loop

for (uint32_t address = network_address + 1; address < broadcast_address; address ++) {
}

And from Davis Herring, to convert the prefix length to subnet mask, you can use

uint32_t netmask = ~(((uint32_t)1 << len) - 1);
1

There are a few ways I could see approaching this, it's nice since you have the IP at your disposal due to the initial input. However I feel this thread may point you in the right direction: How to increment an IP address in a loop? [C]

Let me know.

iHazCode
  • 622
  • 4
  • 15