【问题标题】:Correct Way To Modify Existing Code To Loop Through Subnet修改现有代码以循环子网的正确方法
【发布时间】:2018-01-07 06:53:02
【问题描述】:

我正在编写一个端口扫描器,目的是循环遍历整个子网,以查看是否在任何主机上打开了端口 445,以此作为学习 C 编程的一种方式。该程序当前的设置方式是,需要手动输入一个 IP 地址,然后扫描仪就会启动。它运行良好(最终)。

我目前面临的问题:我不确定如何让这个程序扫描整个子网,而不仅仅是单个主机。在研究了这个问题之后,我相信最好的方法是去掉 IP 地址的最后一个八位字节,并让它从 1-254 循环。但是,我不完全确定如何开始处理这个问题。这是我当前的代码(大量注释以澄清):

...
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:我不知道如何修改此代码以去除 IP 地址的最后一个八位字节,并通过将最后一个八位字节替换为 1 - 254 来循环子网。任何反馈、想法或帮助高度赞赏!在 C 世界中仍然非常初级。

【问题讨论】:

  • strncpy 来自空字符串没有意义。你的意思是memset or =0
  • @DavisHerring 很有趣,感谢您的反馈并抓住了这一点!立即查看详细信息。
  • 你在问这个问题,那么你没有看的太长了(TL;DR:)??

标签: c subnet port-scanning


【解决方案1】:

子网不仅仅是“最后一个字节”。相反,在 CIDR 中有一个前缀长度/子网掩码。您只需要子网中的一个地址,子网掩码无符号整数,但按主机字节顺序,(您需要使用ntohlinet_addrhtonl 的返回值上再次将整数转换为可以存储到s_addr 中的地址。

  • &amp; 带有子网掩码的主机地址来获取网络地址。

  • |网络地址加上的掩码得到广播地址。

  • 网络中的主机地址是这两个之间的所有数字,因此您可以编写一个从network_address + 1 开始并以broadcast_address - 1 结束的for 循环。

因此,如果您的主机地址是 10.24.41.169,前缀长度是 23,则十六进制地址是 0x0A1829A9。网络掩码有 23 个第一位设置为 1,其余为 0,即0b11111111111111111111111000000000,即十六进制的0xFFFFFE00

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

现在网络地址是host &amp; netmask

uint32_t network_address = host & netmask;

广播地址为network_address | ~netmask;host_address | ~netmask

uint32_t network_address = host_address | ~netmask;

子网内的地址可以通过相当无脑的for循环生成

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

并且来自 Davis Herring,要将前缀长度转换为子网掩码,您可以使用

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

【讨论】:

  • 给定前缀len,您可以使用~((1u&lt;&lt;len)-1u) 制作网络掩码。
  • 非常感谢您提供的非常有帮助的答案!
【解决方案2】:

我可以通过几种方法来解决这个问题,这很好,因为由于初始输入,您可以使用 IP。但是我觉得这个线程可能会为您指明正确的方向: How to increment an IP address in a loop? [C]

告诉我。

【讨论】:

猜你喜欢
  • 2021-09-20
  • 1970-01-01
  • 2012-01-22
  • 2014-04-08
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 1970-01-01
  • 2017-08-17
相关资源
最近更新 更多