Linux网络编程:原始套接字的魔力【上】

基于原始套接字编程
       在开发面向连接的 TCP和面向无连接的 UDP程序时,我们所关心的核心问题在于数据收发层面,数据的传输特性由 TCPUDP来保证:
       也就是说,对于 TCPUDP的程序开发,焦点在 Data字段,我们没法直接对 TCPUDP头部字段进行赤裸裸的修改,当然还有 IP头。换句话说,我们对它们头部操作的空间非常受限,只能使用它们已经开放给我们的诸如源、目的 IP,源、目的端口等等。
       今天我们讨论一下原始套接字的程序开发,用它作为入门协议栈的进阶跳板太合适不过了。 OK闲话不多说,进入正题。
       原始套接字的创建方法也不难: socket(AF_INET, SOCK_RAW, protocol)
       重点在 protocol字段,这里就不能简单的将其值为 0了。在头文件 netinet/in.h中定义了系统中该字段目前能取的值,注意:有些系统中不一定实现了 netinet/in.h中的所有协议。源代码的linux/in.h中和netinet/in.h中的内容一样。
       我们常见的有 IPPROTO_TCPIPPROTO_UDPIPPROTO_ICMP,在博文“ (十六)洞悉linux下的Netfilter&iptables:开发自己的hook函数【实战】(下) ”中我们见到该 protocol字段为 IPPROTO_RAW时的情形,后面我们会详细介绍。
       用这种方式我就可以得到原始的 IP包了,然后就可以自定义 IP所承载的具体协议类型,如 TCPUDPICMP,并手动对每种承载在 IP协议之上的报文进行填充。接下来我们看个最著名的例子 DOS攻击的示例代码,以便大家更好的理解如何基于原始套接字手动去封装我们所需要 TCP报文。
       先简单复习一下 TCP报文的格式,因为我们本身不是讲协议的设计思想,所以只会提及和我们接下来主题相关的字段,如果想对 TCP协议原理进行深入了解那么《 TCP/IP详解卷 1》无疑是最好的选择。
       我们目前主要关注上面着色部分的字段就 OK了,接下来再看看 TCP3次握手的过程。 TCP3次握手的一般流程是:
(1) 第一次握手:建立连接时,客户端 A发送 SYN(SEQ_NUMBER=j)到服务器 B,并进入 SYN_SEND状态,等待服务器 B确认。
(2) 第二次握手:服务器 B收到 SYN包,必须确认客户 ASYN(ACK_NUMBER=j+1),同时自己也发送一个 SYN(SEQ_NUMBER=k),即 SYN+ACK包,此时服务器 B进入 SYN_RECV状态。
(3) 第三次握手:客户端 A收到服务器 BSYNACK包,向服务器 B发送确认包 ACK(ACK_NUMBER=k+1),此包发送完毕,客户端 A和服务器 B进入 ESTABLISHED状态,完成三次握手。
 至此 3次握手结束, TCP通路就建立起来了,然后客户端与服务器开始交互数据。上面描述过程中, SYN包表示 TCP数据包的标志位 syn=1,同理, ACK表示 TCP报文中标志位 ack=1SYN+ACK表示标志位 syn=1ack=1同时成立。
原始套接字还提供了一个非常有用的参数 IP_HDRINCL

1、当开启该参数时:我们可以从IP报文首部第一个字节开始依次构造整个IP报文的所有选项,但是IP报文头部中的标识字段(设置为0)IP首部校验和字段总是由内核自己维护的,不需要我们关心。

你可能感兴趣的:( ,基于原始套接字编程)