原始套接字编程
原始套接字使一种非面向连接的,c/s传输方式的网络编程。使用原始套接字编程进行服务器端与客户端的通信前,都要创建各自的套接字,然后对应的套接字进行数据传输。在数据传输过程中,需要使用sendto()函数和recvfrom()函数进行发送与接收,再发送与接收函数中设置相应的IP地址。
原始套接字往往应用于高级网络编程,例如网络嗅探器sniffer、拒绝服务攻击DoS、IP欺骗等。并且还可以通过原始套接字来模拟IP的一些实用工具,例如PING命令。
创建函数
原始套接字编程是SOCK_RAW类型的套接字
int sockfd;
sockfd=socket(AF_INET,SOCK_RAW,protocol);
protocol通常设置为0,还有下面4种取值
- IPPROTO_IP
- IPRROTO_ICMP
- IPRROTO_TCP
- IPRROTO_UDP
注:在Linux中,为了保护网络系统的安全,规定只有超级用户才能创建原始套接口的权限。
设置套接字选项
setsockopt()函数主要用于实现套接字相关的选项设置当前值。
#include<sys/types.h>
#include<sys/socket.h>
int setsockopt(int s,int level,int optname,const void *optval,socklen_t optlen);
s:套接字描述符
level:选择定义的层次,如IPPROTO_IP
optname:套接字选项的名称,如IP_HDRINCL表示要构建IP头部
optval:指向存放选项数据的缓冲区的指针
optlen:缓冲区的长度
调用成功返回0;失败返回-1并设置相应的错误信息。
原始套接字的发送与接收
- 发送报文的原则
- 通常,可以使用sendto()函数指定发送的目的地址,对数据进行传送。但如果已经调用bind()函数绑定了目标地址,则可以使用write()函数或者send()函数发送数据。
- 如果使用了setsockopt()设置了IP_RINCL,则发送的数据缓冲区指向IP头部第一个字节的头部,用户发送的数据包含IP头部之后的所有数据,需要用户自己填写IP头部和计算校验和及所包含数据的处理和计算
- 如果没有设置IP_RINCL,则发送缓冲区指向IP头部后面数据区域的第一个字节,不需要用户填写IP头部,IP头部的填写由内核完成,并由内核进行校验和计算。
- 接收报文的特点
- 对于ICMP协议,绝大部分数据都可以通过原始套接字获得(回显请求,相应,时间戳请求等)
- 接收的UDP和TCP协议的数据不会传给任何原始套接字接口,这些协议的数据需要通过数据链路层获得
- 如果IP以分片形式到达,则所有分片都已经接收到并重组后才传给原始套接字
- 内核不能识别的协议&