📜  用 C 创建 PortScanner

📅  最后修改于: 2021-10-21 05:31:34             🧑  作者: Mango

想象一个停泊着许多私人船只的海湾。该位置称为海港,字面意思是海上或海上的港口。每个想要停靠在那里,请求登陆服务的人都使用同一个端口。海港使用分配给单个船只的泊位编号。港口名称和泊位号组合成船舶识别的“谁、什么、在哪里”。

ip地址和端口的概念类似。这里 sea_port_name 类似于 IP 地址,而后者与 network_port_no 匹配。

端口编号是为了一致性和编程。最常用和最著名的端口是编号为 0 到 1023 的端口,专供 Internet 使用,但它们可以扩展到更高级别以用于特殊目的。每个端口集或范围都被分配了专门的工作或功能,这通常就是他们所做的。通常,所有相同的系统服务或功能在接收服务器上使用相同的端口号,并且它们在任何情况下都保持一致。

当犯罪分子以入室盗窃为目标时,通常他或她检查的第一件事是是否有打开的窗户或门可以进入房屋。安全技术人员经常使用称为端口扫描器的设备/软件,使他们能够扫描所有端口以审计计算机的漏洞。任何时候在个人计算机上打开端口时,都可能会丢失数据、发生病毒,有时甚至会导致系统完全受损。

开发端口扫描器并不像看起来那么困难。扫描仪的最终结果如下:

INPUT : IPv4 address, Port Range
FUNCTION : Enter an IP address and a port range 
           where the program will then attempt to
           find open ports on the given computer 
           by connecting to each of them. On any 
           successful connection ports, mark the 
           port as open.
OUTPUT : Status of port (open/closed)

创建端口扫描器的三步过程

第 1 步:创建 main()

我们创建了一个 main()函数,它接受所需的参数(server_ip、start_port、end_port)。服务器 IP 必须是 IPv4,但我们也可以将其扩展为接受 IPv6。自己试试!!

int main(int argc, char *argv[])
{
    if (argc < 4)
    {
        printf ("Please enter the server IP address"
                " and range of ports to be scanned\n");
        printf ("USAGE: %s IPv4 First_Port Last_Port\n", 
                argv[0]);
        exit(1);
    }
    char tIP[16] = {0};
    strcpy(tIP, argv[1]); // Copy the IPv4 address
    char First_Port[6] = {0};
    strcpy(First_Port, argv[2]); // Copy the start_port
    char Last_Port[6] = {0};
    strcpy(Last_Port, argv[3]); // Copy the end_port

    // Start port-scanner
    port_scanner(tIP, First_Port, Last_Port);
    return 0;
}

第 2 步:创建 port_scanner()

  • 创建一个新函数port_scanner()。我们遍历提供的范围内的所有端口,然后检查每个端口。
  • 创建一个“struct addrinfo 提示”并用适当的值初始化它。
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;

‘hints’ 是指向 struct addrinfo 的可选指针,如 .此结构可用于提供有关调用者支持或希望使用的套接字类型的提示。 – 来自 FreeBSD 手册页。

  • 为我们将从服务器获取的 server_address 初始化一个指针。
    现在,使用适当的参数调用“getaddrinfo(tIP, tport, &hints, &serv_addr)” 。 getaddrinfo()函数分配并初始化一个 addrinfo 结构的链表,一个用于匹配节点和服务的每个网络地址,受提示施加的任何限制,并返回一个指向第 4 段中的链表开头的指针,在这种情况下“ serv_addr” 。链表中的项由ai_next字段链接。

附加信息:
链表可能有多个 addrinfo 结构的原因有多种,包括:网络主机是多宿主的,可通过多种协议访问(例如,AF_INET 和 AF_INET6);或者从多种套接字类型(例如,一个 SOCK_STREAM 地址和另一个 SOCK_DGRAM 地址)提供相同的服务。
通常,应用程序应尝试按照地址返回的顺序使用这些地址。

第 3 步:连接到插座

遍历链表中接收到的所有addrinfo,创建socket。 “socket()”的值存在于上面获得的 addrinfo 结构中。 (链接列表的每个节点都使用指针“temp”遍历。)

sockfd = socket(temp->ai_family, temp->ai_socktype, 
                temp->ai_protocol);
if (sockfd < 0) 
{
     printf("Port %d is NOT open.\n", port);
     continue; 
}

如果套接字创建失败,则尝试使用其他节点中的值。一旦套接字创建成功,尝试使用“connect()”连接到它。如果连接成功,那么恭喜,套接字已打开,否则尝试使用其他 addrinfo 节点。如果它们都不能从linked_list 中工作,则套接字已关闭。这是相同的代码,

status = connect(sockfd, temp->ai_addr, 
                 temp->ai_addrlen);
if (status<0) 
{
    printf("Port %d is NOT open.\n", port);
    close(sockfd);
    continue;
}

printf("Port %d is open.\n", port);
close(sockfd);

“freeaddrinfo()”函数释放为动态分配的链表“serv_addr”分配的内存。使用 this 代替“free()”是一个很好的做法。

本教程的完整源代码可以从这里下载。

注意:这个程序的代码并不长,但是如何使用 getaddrinfo 导出地址很重要。几乎所有 C 语言中的网络应用程序都有类似的前 2 个步骤。第 3 步取决于应用程序的目的

有关 freeaddrinfo 返回的结构的更多信息,请阅读此文档和套接字参数的详细信息,请阅读此文档。

关于作者:

Pinkesh Badjatiya来自 IIIT 海得拉巴。他是个极客,拥有大量值得寻找的项目。他的项目工作可以在这里看到。

如果您还想在这里展示您的博客,请参阅 GBlog,了解 GeeksforGeeks 上的客座博客写作。