修改现有代码以循环遍历子网的正确方法
Correct Way To Modify Existing Code To Loop Through Subnet
我正在编写一个端口扫描器,目的是循环遍历整个子网,以查看端口 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 世界中仍然很初级。
我可以通过几种方法来解决这个问题,这很好,因为由于初始输入,您可以随意使用 IP。但是我觉得这个线程可能会为您指明正确的方向:
How to increment an IP address in a loop? [C]
告诉我。
子网不只是 "the last byte"。相反,在 CIDR 中有一个前缀 length/subnet 掩码。您只需要子网中的一个地址,子网掩码为无符号整数,但在主机字节顺序, (你需要在inet_addr
和htonl
的return值上使用ntohl
将整数再次转换为可以存储到[=18中的地址=]).
你&
主机地址加上子网掩码得到网络地址。
你|
网络地址与掩码的反得到广播地址。
网络中的主机地址就是这2之间的所有数字,所以你可以写一个从[=21开始的for循环=] 并以 broadcast_address - 1
.
结尾
因此,如果您的主机地址为 10.24.41.169,前缀长度为 23
,则十六进制地址为 0x0A1829A9。网络掩码的前 23 位设置为 1,其余设置为 0,即 0b11111111111111111111111000000000
,即十六进制的 0xFFFFFE00
。
uint32_t host = 0x0A1829A9;
uint32_t netmask = 0xFFFFFE00;
现在网络地址是host & 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);
我正在编写一个端口扫描器,目的是循环遍历整个子网,以查看端口 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 世界中仍然很初级。
我可以通过几种方法来解决这个问题,这很好,因为由于初始输入,您可以随意使用 IP。但是我觉得这个线程可能会为您指明正确的方向: How to increment an IP address in a loop? [C]
告诉我。
子网不只是 "the last byte"。相反,在 CIDR 中有一个前缀 length/subnet 掩码。您只需要子网中的一个地址,子网掩码为无符号整数,但在主机字节顺序, (你需要在inet_addr
和htonl
的return值上使用ntohl
将整数再次转换为可以存储到[=18中的地址=]).
你
&
主机地址加上子网掩码得到网络地址。你
|
网络地址与掩码的反得到广播地址。网络中的主机地址就是这2之间的所有数字,所以你可以写一个从[=21开始的for循环=] 并以
broadcast_address - 1
. 结尾
因此,如果您的主机地址为 10.24.41.169,前缀长度为 23
,则十六进制地址为 0x0A1829A9。网络掩码的前 23 位设置为 1,其余设置为 0,即 0b11111111111111111111111000000000
,即十六进制的 0xFFFFFE00
。
uint32_t host = 0x0A1829A9;
uint32_t netmask = 0xFFFFFE00;
现在网络地址是host & 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);