原始套接字

使用原始套接字

  • 原始套接字是允许访问底层传输协议的一种套接字类型。使用原始套接字,需要知道许多下层协议的知识。
  • 原始套接字有两种类型
    • 在IP头中使用预定义的协议,如ICMP
    • 在IP头中使用自定义的协议
  • 创建原始套接字的函数也是socket或WSAScocket,只不过要将套接字的类型 指定为SOCK_RAW
SOCKET sEaw=::socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)
  • 创建原始套接字时,socket函数的第三个参数protocol的值将成为IP头协议域的值。IPPROTO_ICMP指定要使用ICMP
  • 原始套接字提供管理原始下层传输的能力,他们可能会被恶意利用,这是一个安全问题,仅Administrator组的成员能够创建SOCK_RAW类型的套接字。任何人都可以在NT下创建原始套接字,但是没有Administrator权限的人不能用它做任何事,因为bind函数会失败。
  • 在上面套接字创建代码中,可以使用ICMP也可以使用IGMP、UDP、IP或者原始IP,对应的宏分别是IPPROTO_IGMP、IPPROTO_UDP、IPPROTO_IP或IPPROTO_RAW。其中IPPROTO_UDP、IPPROTO_IP、IPPROTO_RAW需要有效的IP_HDRINCL选项。
  • 使用恰当的协议标志创建原始套接字之后,便可以在发送和接收diao调用中使用此套接字句柄了。无论IP_HDRINCL选项是否设置,在原始套接字上接收到的数据都将包含IP头

ICMP编程

  • 在网络层除了IP之外,还有一些控制协议,有ICMP、ARP、DHCP等。这里主要讲述ICMP,以及如何使用原始套接字编写ICMP程序。

  • ICMP校验和的计算

    • 互联网上的操作由路由器仅仅监控者,当有异常发生。具体事件通过ICMP(网间控制报文协议)报道。如目的不可达、TTL超时等。ICMP也用来测试互联网。
    • 每个ICMP消息都装在IP封包中,所以它使用IP寻址。ICMP消息格式。
  • 第一个域是ICMP的消息类型,通常可以分为请求消息和错误报告消息两类。第二个域是代码域,进一步定义了请求或消息的类型。第三个域是checksum域,是16位的ICMP头的补足校验和,它提供了错误检测。计算校验和时要包含ICMP头和它实际数据。

  • ICMP的内容取决于ICMP类型和代码,如下所示为常用ICMP类型和功能码,ICMP封包的类型和功能码规定了ICMP头后面的内容。

  • 校验和的计算

    • 发送ICMP报文时必须自己计算校验和,将他填入ICMP头部对应的域中。校验和的计算方法是:将数据以子为单位累加到一个双子中,如果数据长度为奇数,最后一个字将要被扩展到字,累加的结果是一个双字,最后将这个双字的高16位和低16位相加后取反,便得到了校验和。

PING程序实例

  • ping经常用来确定主机是否存在,是否可以到达。通过产生一个ICMP的回显请求,并驱使它到感兴趣的主机,便可以确认是否可以成功达到那个机器,当然,这不能保证可以使用传统套接字连接到那个主机的进程。大多数主机提供关闭ICMP回显请求的功能,常常发生在运行防火墙的情况下,本质上ping执行一下步骤:
    • 创建一些类型为IPPROTO_ICMP的原始套接字,设置套接字的属性
    • 创建并初始化ICMP封包
    • 调用sendto函数向远程主机发送ICMP请求
    • 调用recvfrom函数接收ICMP响应
  • 初始化ICMP头时先初始化消息类型和代码域,之后回显请求头。
  • 远程机器收到ICMP回显请求之后,会向发送者发回一个回显响应请求,如果由于某些原因主机不可达,相应的ICMP错误消息会被途中的路由器发送回来。如果物理网络连接没有问题,远程主机也存在,但是这个网络消息没有相应,对recvfrom函数的调用就会超时。

路由跟踪

  • 一个有用的IP网络工具是路由跟踪程序Traceroute。使用它可以确定路由器的IP地址,也就是网络上到达特定主机所经过的计算机。使用ping,利用IPV4可选头总的记录路由器选项,也可以确定中间路由器的ip地址,但是ping受可选头中最大空间的限制,仅能记录九个ip地址。
  • Traceroute利用的办法就是发送一个UDP封包到目的地址,递加TTL值。初始情况下TTL=1,意味着到达第一个路由器时TTL将中止这个中止会促使路由器产生一个ICMP超时封包,当TTL足够大时能够达到终端mICMP端口不可达多数会被返回。收集每个ICMP消息便可得到封包途径路由器。
  • routetracer程序开始运行时创建了两个套接字,一个是用于接收ICMP封包的原始套接字是Raw另一个是用于发送TTL不断增加的UDP封包套接字sSend,在sSend套接字上发送UDP封包,逐渐增加TTL的值,每次超时一个ICMP消息就会被发送回来。
    实现ping:https://github.com/MikotoMisakas/Network_programming/blob/develop/PING/PING/ping.cpp
    路由ip:https://github.com/MikotoMisakas/Network_programming/blob/develop/GetRoutingIp/GetRoutingIp/getRoutingip.cpp
posted @ 2020-08-18 15:29  一生热爱  阅读(939)  评论(0编辑  收藏  举报