【大牛说】

码大牛,成长于传智播客和黑马程序员的专家型顾问。大牛老师从今天开始推出一个固定栏目,推出关于技术、教学话题的干货和想法。每周二、周四,大牛老师会在微信公众号(boxuegu)和QQ(2011168841)空间同步更新。

经常在电影里看到超级黑客高手,在电脑前轻松“黑”进别人的安全系统的场景,纯熟自如地输入一大堆复杂的代码,瞬间破解完成。那装逼指数,绝对满分。直到接触了一点计算机底层的知识,了解了一点网络安全,才知道黑客入侵的第一屏障就是原始套接字。
 

聊到了套接字,就和大家说一说 
老师和大牛聊天的时候,反馈对TCP/UDP已经非常了解了,但是对原始套接字的原理和规则还是比较陌生。大牛又接连问了几位老师,普遍都是这样的反馈。


所以,大牛在这里针对“原始套接字”给大家简单补上一课,其实原始套接字不但广泛应用于高级网络编程,也是一种广泛的黑客手段。著名的网络sniffer(一种基于被动侦听原理的网络分析方式)、拒绝服务攻击(DOS)、IP欺骗等都可以通过原始套接字实现。需要注意的是,必须在管理员权限下才能使用原始套接字。OK闲话不多说,进入正题。
 

经典的“三次握手”

先简单复习一下TCP报文的格式。


从上图我们分析一次,TCP的3次握手情况:

(1) 第一次握手:建立连接时,客户端A发送SYN包(SEQ_NUMBER=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。

(2) 第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK_NUMBER=j+1),同时自己也发送一个SYN包(SEQ_NUMBER=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。

(3) 第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK_NUMBER=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。

 至此3次握手结束,TCP通路就建立起来了,然后客户端与服务器开始交互数据。

上面的TCP的3次握手流程是不是很熟悉?


浅析原始套接字

原始套接字(SOCK_RAW)与标准套接字(SOCK_STREAM、SOCK_DGRAM)的区别在于原始套接字直接置“根”于操作系统网络核心(NetworkCore),而 SOCK_STREAM、SOCK_DGRAM 则“悬浮”于 TCP 和 UDP 协议的外围。流式套接字只能收发 TCP 协议的数据,数据报套接字只能收发UDP 协议的数据,原始套接字可以收发内核没有处理(网卡上原生态)的数据包。


1. 原始套接字的创建:

#include  <sys/types.h>     

#include  <sys/socket.h>

#include <netinet/ether.h>// ETH_P_ALL

int socket(int family, int type,int protocol);

功能:创建套接字

参数:

family:协议族,创建原始套接字写 PF_PACKET

type:  套接字类,这里写SOCK_RAW

protocol:协议类别,指定可以接收或发送的数据包类型,不能写 “0”,取值如下,注意,传参时需要用 htons()进行字节序转换。

ETH_P_IP:IPV4数据包

ETH_P_ARP:ARP数据包

ETH_P_ALL:任何协议类型的数据包

返回值:

成功(>0):套接字,这里为链路层的套接字

失败(<0):出错

 

2.  获取链路层的数据包:

#include <sys/types.h>

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buf, size_t

nbytes, int flags, structsockaddr *from, socklen_t *addrlen);

功能:获取链路层的数据包

参数:

sockfd : 原始套接字

buf:接收数据缓冲区

nbytes : 接收数据缓冲区的大小

flags:套接字标志(常为0)

from:这里没有用,写 NULL

addrlen:这里没有用,写NULL

返回值:

成功:接收到的字符数

失败: - 1

 

3. 发送自定义的数据包:

#include <sys/types.h>

#include <sys/socket.h>

ssize_t sendto(int sockfd, constvoid *buf, size_t nbytes, int flags, const struct sockaddr *to, socklen_taddrlen);

功能:发送自定义的数据包

参数:

sockfd:原始套接字

buf:发送数据缓冲区

nbytes : 发送数据缓冲区的大小

flags:一般为 0

to:本机网络接口,指发送的数据应该从本机的哪个网卡出去

addrlen:to 所指向内容的长度

返回值:

成功:发送数据的字符数

失败: - 1

 

4. 获取本机网络接口:

#include <net/if.h>//struct ifreq

#include <sys/ioctl.h> //ioctl、SIOCGIFADDR

#include<netpacket/packet.h> // struct sockaddr_ll

struct sockaddr_ll sll;                    //原始套接字地址结构

struct ifreq ethreq;                       //网络接口地址

strncpy(ethreq.ifr_name,"ens33", IFNAMSIZ);     //指定网卡名称

写到这,大家对原始套接字的使用方法以及TCP/IP协议结构原理等知识有一个基本的认识。原始套接字要学的东西很深,有这方面教学需要或者对网络安全感兴趣的老师可以继续研究,但是千万不要利用原始套接字来做一名黑客哦!

教学好助手(boxuegu)

教IT、学IT都会关注的公众号

定期推送IT技术、教学干货和教师话题思考