zoukankan      html  css  js  c++  java
  • VC++实现遍历所有网络端口


    在网络技术中,端口(Port)有好几种意思。集线器、交换机、路由器的端口指的是连接其他网络设备的接口,如RJ-45端口、Serial端口等。我们 这里所指的端口不是指物理意义上的端口,而是特指TCP/IP协议中的端口,是逻辑意义上的端口。


    协议端口


      如果把IP地址比作一间房子 ,端口就是出入这间房子的门。真正的房子只有几个门,但是一个IP地址的端口 可以有65536(即:2^16)个之多!端口是通过端口号来标记的,端口号只有整数,范围是从0 到65535(2^16-1)。
      在Internet上,各主机间通过TCP/IP协议发送和接收数据包,各个数据包根据其目的主机的ip地址来进行互联网络中的路由选择。可见,把数据包顺利的传送到目的主机是没有问题的。问题出在哪里呢?我们知道大多数操作系统都支持多程序(进程)同时运行,那么目的主机应该把接收到的数据包传送给众多同时运行的进程中的哪一个呢?显然这个问题有待解决,端口机制便由此被引入进来。
      本地操作系统会给那些有需求的进程分配协议端口(protocol port,即我们常说的端口),每个协议端口由一个正整数标识,如:80,139,445,等等。当目的主机接收到数据包后,将根据报文首部的目的端口号,把数据发送到相应端口,而与此端口相对应的那个进程将会领取数据并等待下一组数据的到来。说到这里,端口的概念似乎仍然抽象,那么继续跟我来,别走开。
      端口其实就是队,操作系统为各个进程分配了不同的队,数据包按照目的端口被推入相应的队中,等待被进程取用,在极特殊的情况下,这个队也是有可能溢出的,不过操作系统允许各进程指定和调整自己的队的大小。
      不光接受数据包的进程需要开启它自己的端口,发送数据包的进程也需要开启端口,这样,数据包中将会标识有源端口,以便接受方能顺利地回传数据包到这个端口。
      端口详解
      在开始讲什么是端口之前,我们先来聊一聊什么是 port 呢?常常在网络上听说『我的主机开了多少的 port ,会不会被入侵呀!?或者是说『开那个 port 会比较安全?又,我的服务应该对应什么 port 呀?呵呵!很神奇吧!怎么一部主机上面有这么多的奇怪的 port 呢?这个 port 有什么作用呢?
      由于每种网络的服务功能都不相同,因此有必要将不同的封包送给不同的服务来处理,所以啰,当你的主机同时开启了FTP与 WWW 服务的时候,那么别人送来的资料封包,就会依照 TCP 上面的 port 号码来给 FTP 这个服务或者是 WWW 这个服务来处理,当然就不会搞乱啰!(注:嘿嘿!有些很少接触到网络的朋友,常常会问说:咦!为什么你的计算机同时有 FTP、WWW、E-Mail 这么多服务,但是人家传资料过来,你的计算机怎么知道如何判断?计算机真的都不会误判吗?!现在知道为什么了吗?!对啦!就是因为 port 不同嘛!你可以这样想啦,有一天,你要去银行存钱,那个银行就可以想成是主机,然后,银行当然不可能只有一种业务,里头就有相当多的窗口,那么你一进大门的时候,在门口的服务人员就会问你说:"嗨!你好呀!你要做些什么事?"你跟他说:"我要存钱呀!",服务员接着就会告诉你:喝!那么请前往三号窗口!那边的人员会帮您服务!这个时候你总该不会往其它的窗口跑吧?! ""这些窗口就可以想成是port 啰!所以啦!每一种服务都有特定的 port 在监听!您无须担心计算机会误判的问题呦! )
      · 每一个 TCP 连接都必须由一端(通常为 client )发起请求,这个 port 通常是随机选择大于 1024 以上(因为0-1023一般被用作知名服务器的端口,被预定,如FTP、HTTP、SMTP等)的 port 号来进行!其 TCP 封包会将(且只将) SYN 旗标设定起来!这是整个联机的第一个封包;
      · 如果另一端(通常为 Server ) 接受这个请求的话(当然啰,特殊的服务需要以特殊的 port 来进行,例如 FTP 的 port 21 ),则会向请求端送回整个联机的第二个封包!其上除了 SYN 旗标之外同时还将 ACK 旗标也设定起来,并同时在本机端建立资源以待联机之需;
      · 然后,请求端获得服务端第一个响应封包之后,必须再响应对方一个确认封包,此时封包只带 ACK 旗标(事实上,后继联机中的所有封包都必须带有 ACK 旗标);
      · 只有当服务端收到请求端的确认( ACK )封包(也就是整个联机的第三个封包)之后,两端的联机才能正式建立。这就是所谓的 TCP 联机的'三次握手( Three-Way Handshake )'的原理。
      经过三向交握之后,呵呵!你的 client 端的 port 通常是高于 1024 的随机取得的 port,至于主机端则视当时的服务是开启哪一个 port 而定,例如 WWW 选择 80 而 FTP 则以 21 为正常的联机信道!
      总而言之,我们这里所说的端口,不是计算机硬件的I/O端口,而是软件形式上的概念。根据提供服务类型的不同,端口分为两种,一种是TCP端口,一种是UDP端口。计算机之间相互通信的时候,分为两种方式:一种是发送信息以后,可以确认信息是否到达,也就是有应答的方式,这种方式大多采用TCP协议;一种是发送以后就不管了,不去确认信息是否到达,这种方式大多采用UDP协议。对应这两种协议的服务提供的端口,也就分为TCP端口和UDP端口。
      那么,如果攻击者使用软件扫描目标计算机,得到目标计算机打开的端口,也就了解了目标计算机提供了哪些服务。我们都知道,提供服务就一定有服务软件的漏洞,根据这些,攻击者可以达到对目标计算机的初步了解。如果计算机的端口打开太多,而管理者不知道,那么,有两种情况:一种是提供了服务而管理者没有注意,比如安装IIS的时候,软件就会自动增加很多服务,而管理员可能没有注意到;一种是服务器被攻击者安装木马,通过特殊的端口进行通信。这两种情况都是很危险的,说到底,就是管理员不了解服务器提供的服务,减小了系统安全系数。


    端口详解


      端口是指接口电路中的一些寄存器,这些寄存器分别用来存放数据信息、控制信息和状态信息,相应的端口分别称为数据端口、控制端口和状态端口。
      电脑运行的系统程序,其实就像一个闭合的圆圈,但是电脑是为人服务的,他需要接受一些指令,并且要按照指令调整系统功能来工作,于是系统程序设计者,就把这个圆圈截成好多段,这些线段接口就叫端口(通俗讲是断口,就是中断),系统运行到这些端口时,一看端口是否打开或关闭,如果关闭,就是绳子接通了,系统往下运行,如果端口是打开的,系统就得到命令,有外部数据输入,接受外部数据并执 行。
    TCP端口?
      TCP:Transmission Control Protocol 传输控制协议TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议,由IETF的RFC 793说明(specified)。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,UDP是同一层内另一个重要的传输协议。
    UDP端口?
      UDP:UDP是ISO参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP 协议基本上是IP协议与上层协议的接口。UDP协议适用端口分辨运行在同一台设备上的多个应用程序。


    端口作用


      我们知道,一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等,这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP 地址与网络服务的关系是一对多的关系。实际上是通过“IP地址+端口号”来区分不同的服务的。
      需要注意的是,端口并不是一一对应的。比如你的电脑作为客户机访 问一台WWW服务器时,WWW服务器使用“80”端口与你的电脑通信,但你的电脑则可能使用“3457”这样的端口。
      动态端口(Dynamic Ports)
      动态端口的范围是从1024到65535。之所以称为动态端口,是因为它 一般不固定分配某种服务,而是动态分配。动态分配是指当一个系统进程或应用 程序进程需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配 一个供它使用。当这个进程关闭时,同时也就释放了所占用的端口号。
      端口在入侵中的作用
      有人曾经把服务器比作房子,而把端口比作通向不同房间(服务)的门,如果不考虑细节的话,这是一个不错的比喻。入侵者要占领这间房子,势必要破门而入(物理入侵另说),那么对于入侵者来说,了解房子开了几扇门,都是什么样的门,门后面有什么东西就显得至关重要。
      入侵者通常会用扫描器对目标主机的端口进行扫描,以确定哪些端口是开放的,从开放的端口,入侵者可以知道目标主机大致提供了哪些服务,进而猜测可能存在的漏洞,因此对端口的扫描可以帮助我们更好的了解目标主机,而对于管理员,扫描本机的开放端口也是做好安全防范的第一步。
      分类
      软件领域的端口一般指网络中面向连接服务和无连接服务的通信协议端口,是一种抽象的软件结构,包括一些数据结构和I/O(基本输入输出)缓冲区。
      面向连接服务和无连接服务
      可以先了解面向连接和无连接协议(Connection-Oriented and ConnectionlessProtocols)面向连接服务的主要特点有:面向连接服务要经过三个阶段:数据传输前,先建立连接,连接建立后再传输数据,数据传送完后,释放连接。面向连接服务,可确保数据传送的次序和传输的可靠性。无连接服务的特点是:无连接服务只有传输数据阶段。消除了除数据通信外的其它开销。只要发送实体是活跃的,无须接收实体也是活跃的。它的优点是灵活方便、迅速,特别适合于传送少量零星的报文,但无连接服务不能防止报文的丢失、重复或失序。
      区分"面向连接服务"和"无连接服务"的概念
      区分特别简单、形象的例子是:打电话和写信。两个人如果要通电话,必须先建立连接--拨号,等待应答后才能相互传递信息,最后还要释放连接--挂电话。写信就没有那么复杂了,地址姓名填好以后直接往邮筒一扔,收信人就能收到。TCP/IP协议在网络层是无连接的(数据包只管往网上发,如何传输和到达以及是否到达由网络设备来管理)。而"端口",是传输层的内容,是面向连接的。协议里面低于1024的端口都有确切的定义,它们对应着因特网上常见的一些服务。
      这些常见的服务划分
      划分为使用TCP端口(面向连接如打电话)和使用UDP端口(无连接如写信)两种。
      网络中可以被命名和寻址的通信端口是操作系统的一种可分配资源。由网络OSI(开放系统互联参考模型,Open System Interconnection Reference Model)七层协议可知,传输层与网络层最大的区别是传输层提供进程通信能力,网络通信的最终地址不仅包括主机地址,还包括可描述进程的某种标识。所以TCP/IP协议提出的协议端口,可以认为是网络通信进程的一种标识符。
      应用程序(调入内存运行后一般称为:进程)通过系统调用与某端口建立连接(binding,绑定)后,传输层传给该端口的数据都被相应的进程所接收,相应进程发给传输层的数据都从该端口输出。在TCP/IP协议的实现中,端口操作类似于一般的I/O操作,进程获取一个端口,相当于获取本地唯一的I/O文件,可以用一般的读写方式访问类似于文件描述符,每个端口都拥有一个叫端口号的整数描述符,用来区别不同的端口。由于TCP/IP传输层的TCP和UDP两个协议是两个完全独立的软件模块,因此各自的端口号也相互独立。如TCP有一个255号端口,UDP也可以有一个255号端口,两者并不冲突。端口号有两种基本分配方式:第一种叫全局分配这是一种集中分配方式,由一个公认权威的中央机构根据用户需要进行统一分配,并将结果公布于众,第二种是本地分配,又称动态连接,即进程需要访问传输层服务时,向本地操作系统提出申请,操作系统返回本地唯一的端口号,进程再通过合适的系统调用,将自己和该端口连接起来(binding,绑定)。TCP/IP端口号的分配综合了以上两种方式,将端口号分为两部分,少量的作为保留端口,以全局方式分配给服务进程。每一个标准服务器都拥有一个全局公认的端口叫周知端口,即使在不同的机器上,其端口号也相同。剩余的为自由端口,以本地方式进行分配。TCP和UDP规定,小于256的端口才能作为保留端口。
      按端口号可分为3大类
      (1)公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。
      (2)注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。
      (3)动态和/或私有端口(Dynamicand/orPrivatePorts):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。但也有例外:SUN的RPC端口从32768开始。
      系统管理员可以"重定向"端口
      一种常见的技术是把一个端口重定向到另一个地址。例如默认的HTTP端口是80,不少人将它重定向到另一个端口,如8080。如果是这样改了。实现重定向是为了隐藏公认的默认端口,降低受破坏率。这样如果有人要对一个公认的默认端口进行攻击则必须先进行端口扫描。大多数端口重定向与原端口有相似之处,例如多数HTTP端口由80变化而来:81,88,8000,8080,8888。同样POP的端口原来在110,也常被重定向到1100。也有不少情况是选取统计上有特别意义的数,象1234,23456,34567等。许多人有其它原因选择奇怪的数,42,69,666,31337。近来,越来越多的远程控制木马(RemoteAccessTrojans,RATs)采用相同的默认端口。如NetBus的默认端口是12345。BlakeR.Swopes指出使用重定向端口还有一个原因,在UNIX系统上,如果你想侦听1024以下的端口需要有root权限。如果你没有root权限而又想开web服务,你就需要将其安装在较高的端口。此外,一些ISP的防火墙将阻挡低端口的通讯,这样的话即使你拥有整个机器你还是得重定向端口。


    端口类型


      TCP端口和UDP端口。由于TCP和UDP 两个协议是独立的,因此各自的端口号也相互独立,比如TCP有235端口,UDP也 可以有235端口,两者并不冲突。
      1.周知端口(Well Known Ports)
      周知端口是众所周知的端口号,范围从0到1023,其中80端口分配给W WW服务,21端口分配给FTP服务等。我们在IE的地址栏里输入一个网址的时候是不必指定端口号的,因为在默认情况下WWW服务的端口 号是“80”。
      网络服务是可以使用其他端口号的,如果不是默认的端口号则应该在 地址栏上指定端口号,方法是在地址后面加上冒号“:”(半角),再加上端口 号。比如使用“8080”作为WWW服务的端口,则需要在地址栏里输入“网址:8080”。
      但是有些系统协议使用固定的端口号,它是不能被改变的,比如139 端口专门用于NetBIOS与TCP/IP之间的通信,不能手动改变。
      2.动态端口(Dynamic Ports)
      动态端口的范围是从1024到65535。之所以称为动态端口,是因为它 一般不固定分配某种服务,而是动态分配。动态分配是指当一个系统进程或应用 程序进程需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配 一个供它使用。当这个进程关闭时,同时也就释放了所占用的端口号。


     */   
    int show_interface_content(const struct intf_entry *object, void *p)   
    {   
        int number;   
        printf("network interface name is :");   
        printf("%s\n", object->intf_name);   
        /* 输出网络接口的名字 */   
        printf("flags: %d\n", object->intf_flags);   
        /* 输出网络接口参数标志 */   
        printf("flags including:\n");   
        if (object->intf_flags &INTF_FLAG_UP)   
         /* 判断是否是激活状态,UP */   
            printf("UP\n");   
        if (object->intf_flags &INTF_FLAG_LOOPBACK)   
         /* 判断是否是回路 */   
            printf("LOOPBACK\n");   
        if (object->intf_flags &INTF_FLAG_POINTOPOINT)   
         /* 判断是否支持点对点协议 */   
            printf("POINTOPOINT\n");   
        if (object->intf_flags &INTF_FLAG_NOARP)   
         /* 判断是否不支持ARP协议 */   
            printf("NOARP\n");   
        if (object->intf_flags &INTF_FLAG_BROADCAST)   
         /* 判断是否支持广播 */   
            printf("BROADCAST\n");   
        if (object->intf_flags &INTF_FLAG_MULTICAST)   
         /* 判断是否支持多播 */   
            printf("MULTICAST\n");   
        if (object->intf_mtu != 0)   
            printf("mtu: %d\n", object->intf_mtu);   
        /* 输出MTU值 */   
        if (object->intf_addr.addr_type == ADDR_TYPE_IP)   
        {   
            if (object->intf_dst_addr.addr_type == ADDR_TYPE_IP)   
            {   
                printf("address:%s,desination:%s\n", addr_ntoa(&object->intf_addr), addr_ntoa(&object->intf_dst_addr));   
                /* 输出源地址和目的地址 */   
            }   
            else   
                printf("address:%s\n", addr_ntoa(&object->intf_addr));   
            /* 输出源地址 */   
        }   
        if (object->intf_link_addr.addr_type == ADDR_TYPE_ETH)   
            printf("Link Address: %s\n", addr_ntoa(&object->intf_link_addr));   
        /* 输出硬件地址 */   
        for (number = 0; number < object->intf_alias_num; number++)   
            printf("Alias:%s\n", addr_ntoa(&object->intf_alias_addrs[number]));   
        /* 输出所有别名 */   
        printf("-----------------------------------------------------------\n");   
        return (0);   
    }   
    int main()   
    {   
        struct intf_entry *entry;   
        /* 网络接口的数据结构的变量 */   
        intf_t *handle;   
        /* 网络接口操作句柄 */   
        struct addr *interface_address;   
        /* 地址 */   
        char content[1024];   
        /* 内容 */   
        struct addr address;   
        /* 地址 */   
        entry = (struct intf_entry*)content;   
        /* 构造接口信息 */   
        memset(entry, 0, sizeof(*entry));   
        entry->intf_len = sizeof(content);   
        /* 长度 */   
        handle = intf_open();   
        /* 打开接口操作 */   
        printf("show the network interface:\n");   
        intf_loop(handle, show_interface_content, NULL);   
        /* 注册回调函数show_interface_content,循环调用回调函数依次输出每个网络接口的信息 */   
        printf("get the special network interface:\n");   
        strlcpy(entry->intf_name, "eth0", sizeof(entry->intf_name));   
        /* 指定网络接口名字eth0 */   
        intf_get(handle, entry);   
        /* 根据网络接口的名字获取网络接口 */   
        show_interface_content(entry, NULL);   
        /* 显示获得的网路接口的信息 */   
        printf("show the network interface about the IP :\n");   
        addr_aton("192.168.0.3", &address);   
        /* 把字符串形式的IP地址转换为二进制形式的IP地址 */   
        intf_get_src(handle, entry, &address);   
        /* 根据地址获取特定的网络接口 */   
        show_interface_content(entry, NULL);   
        /* 显示此网络接口的信息 */   
        printf("show the network interface about the destination IP:\n");   
        addr_aton("192.168.0.4", &address);   
        /* 把IP地址的字符串形式转换为二进制形式 */   
        intf_get_dst(handle, entry, &address);   
        /* 根据目的地址获取相对应的网络接口 */   
        show_interface_content(entry, NULL);   
        /* 显示获得的网路接口的信息 */   
        strlcpy(entry->intf_name, "eth0", sizeof(entry->intf_name));   
        /* 指定网络接口名字为eth0 */   
        printf("set the network interface unactive:\n");   
        entry->intf_flags &= ~INTF_FLAG_UP;   
        /* 设置网络接口的参数为失效状态 */   
        intf_set(handle, entry);   
        /* 设置指定的网络接口为失效状态 */   
        printf("show the network interface:\n");   
        intf_loop(handle, show_interface_content, NULL);   
        /* 显示所有网络接口的信息 */   
        printf("set the network interface active:\n");   
        entry->intf_flags |= INTF_FLAG_UP;   
        /* 设置网络接口参数为激活状态 */   
        intf_set(handle, entry);   
        /* 设置指定的网络接口为激活状态 */   
        printf("show the network interface:\n");   
        intf_loop(handle, show_interface_content, NULL);   
        /* 显示所有网络接口的信息 */   
        printf("set the network interface can't use ARP protocol :\n");   
        entry->intf_flags |= INTF_FLAG_NOARP;   
        /* 设置网络接口参数为不支持ARP协议 */   
        intf_set(handle, entry);   
        /* 设置指定的网络接口不支持ARP协议 */   
        printf("show the network interface:\n");   
        intf_loop(handle, show_interface_content, NULL);   
        /* 显示所有的网络接口的信息 */   
        printf("set the network interface can use ARP protocol :\n");   
        entry->intf_flags &= ~INTF_FLAG_NOARP;   
        /* 设置网络接口参数为不支持ARP协议 */   
        intf_set(handle, entry);   
        /* 设置特定的网络接口不支持ARP协议 */   
        printf("show the network interface:\n");   
        intf_loop(handle, show_interface_content, NULL);   
        /* 显示所有的网络接口信息 */   
        printf("set the network interface alias:\n");   
        interface_address = &entry->intf_alias_addrs[entry->intf_alias_num++];   
        /* 网络接口的别名 */   
        addr_pton("192.168.0.6", interface_address);   
        /* 把IP地址的字符串形式转换为二进制形式 */   
        intf_set(handle, entry);   
        /* 设置网络接口的别名为"192.168.0.6"。 */   
        printf("show the network interface:\n");   
        intf_loop(handle, show_interface_content, NULL);   
        /* 显示所有网络接口的信息 */   
        printf("set the network interface destination:\n");   
        interface_address = &entry->intf_dst_addr;   
        /* 目的地址 */   
        addr_pton("192.168.0.7", interface_address);   
        /* 把IP地址的字符串形式转换为二进制形式 */   
        intf_set(handle, entry);   
        /* 设置网络接口的目的地址为192.168.0.7 */   
        printf("show the network interface:\n");   
        intf_loop(handle, show_interface_content, NULL);   
        /* 显示所有网络接口的信息 */   
        printf("set the network interface address:\n");   
        interface_address = &entry->intf_addr;   
        /* 网络接口的地址 */   
        addr_pton("192.168.0.8", interface_address);   
        /* 把IP地址的字符串形式转换为二进制形式 */   
        intf_set(handle, entry);   
        /* 设置网络接口的地址为192.168.0.8 */   
        printf("show the network interface:\n");   
        intf_loop(handle, show_interface_content, NULL);   
        /* 显示所有网络接口的信息 */   
        printf("set the network interface link:\n");   
        interface_address = &entry->intf_link_addr;   
        /* 硬件地址 */   
        addr_pton("192.168.0.9", interface_address);   
        /* 把IP地址的字符串形式转换为二进制形式 */   
        intf_set(handle, entry);   
        /* 设置网络接口的硬件地址为192.168.0.8的硬件地址 */   
        printf("show the network interface:\n");   
        intf_loop(handle, show_interface_content, NULL);   
        /* 显示所有网络接口的信息 */   
        intf_close(handle);   
        /* 关闭网络接口操作 */   
    }   


  • 相关阅读:
    java中的 equals 与 ==
    String类的内存分配
    SVN用命令行更换本地副本IP地址
    npoi 设置单元格格式
    net core 微服务框架 Viper 调用链路追踪
    打不死的小强 .net core 微服务 快速开发框架 Viper 限流
    net core 微服务 快速开发框架 Viper 初体验20201017
    Anno 框架 增加缓存、限流策略、事件总线、支持 thrift grpc 作为底层传输
    net core 微服务 快速开发框架
    Viper 微服务框架 编写一个hello world 插件02
  • 原文地址:https://www.cnblogs.com/new0801/p/6177682.html
Copyright © 2011-2022 走看看