某学白糖丝发来问题:
这个题目一看就晓得那位朋友是网路安全相关专业。
好多粉丝以为彭老师知识搞驱动的,
然而虽然作为一个拥有多篇网路合同专利的老手,
网路知识还是比较擅长的!
应用层套接字、组网、网卡驱动都有所涉猎,
目前还缺Linux内核合同栈这块没深入研究,后期会补上。
一、题目总结
题目要求是扫描所有TCP半联接的端口,须要实现的功能如下:
功击方启动任务1,循环向指定服务器端+端口发送SYN数据包,(端口从0开始递增)假如该服务器上有服务打开了这个端口,都会回复SYN+ACK,此时服务端步入SYN_RCVD状态,功击方启动任务2,扫描收到的所有SYN+ACK数据包,假如顾客端收到SYN+ACK,这么说明服务器改端口打开,任务2就可以将所有打开的端口信息复印下来二、TCP基础知识点
解决这个问题必须把握以下几个知识点:
哪些是TCPTCP3次握手哪些是半联接TCP、IP合同头怎么使用Libpcap库线程、进程
整体来说对网路知识的基本功要求还是很高的。关于TCP/IP合同栈这种基础知识点的本文就不列出了。
下边主要加强下这个题目涉及的TCP的知识点。
1.TCP
首先就是我们必须了解TCP合同头:
序列号:在构建联接时由计算机生成的随机数作为其初始值,通过SYN包传给接收端主机linux使用socket通信linux更改ip地址,每发送一次数据,就「累加」一次该「数据字节数」的大小。拿来解决网路包正序问题确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答之后可以觉得在这个序号原先的数据都早已被正常接收。拿来解决不丢包的问题控制位:ACK:该位为1时,「确认应答」的数组变为有效,TCP规定不仅最初构建联接时的SYN包之外该位必须设置为1RST:该位为1时,表示TCP联接中出现异常必须强制断掉联接SYN:该位为1时,表示希望构建联接,并在其「序列号」的数组进行序列号初始值的设定FIN:该位为1时,表示今后不会再有数据发送,希望断掉联接。当通讯结束希望断掉联接时,通讯双方的主机之间就可以互相交换FIN位置为1的TCP段
与本题目相关的是最主要数组是控制位,控制位的操作最主要彰显在3次握手和4次握手。
2.tcp三次握手
开始顾客端和服务器都处于CLOSED状态,之后服务端开始窃听某个端口,步入LISTEN状态:
3.tcp四次挥手
四次挥手过程:
4.TCP状态
TCP合同状态迁移图如下:
5.半联接/全联接
TCP半联接及全联接状态,在服务器的性能剖析中,起着重要的作用,它一般是反应服务端的处理能力
1)半联接队列(synqueue)
顾客端发送SYN包,服务端收到后回复SYN+ACK后,服务端步入SYN_RCVD状态,这个时侯的socket会放在半联接队列。
2)全联接队列(acceptqueue)
当服务端收到顾客端的ACK后,socket会从半联接队列移出到全联接队列。当调用accpet函数的时侯,会从全联接队列的腹部返回可用socket给用户进程。
全联接队列中储存的是已完成TCP三次握手的过程,等待被处理的联接,在顾客端及服务端的状态均为ESTABLISHED
三、抓包举例
要想学好网路,抓包工具是必须把握的。
右图是一口君通过抓包工具抓取的一个完整的tcp3次握手+HTTPGET恳求+4次握手的完整通讯数据包。
怎么抓包,可以参考下边文章:
《一文包你学会网路数据抓包》
B站也有详尽的教学视频:
《教你怎么抓取网路中的数据包!黑客必备技能》
四、socket
关于socketAPI内容,你们可以的参考下边这篇文章
《socket究竟是哪些?》
五、libpcap
libpcap是一个网路数据包捕获函数库,功能十分强悍,Linux下知名的tcpdump就是以它为基础的。
libpcap主要由两部份组成:网路分接头(networktap)和数据过滤器(packetfilter)。
网路分接头从网路设备驱动程序中搜集数据进行拷贝,过滤器决定是否接收该数据包。
libpcap借助BSDpacketfilter(BPF)算法对网卡接收到的链路层数据包进行过滤。
libpcap的包捕获机制就是在数据链路层加一个旁路处理。当一个数据包抵达网路插口时,libpcap首先借助早已创建的套接字从链路层驱动程序中获得该数据包的拷贝,再通过Tap函数将数据包发给BPF过滤器。
BPF过滤器按照用户早已定义好的过滤规则对数据包进行逐一匹配,匹配成功则装入内核缓冲区,并传递给用户缓冲区,匹配失败则直接扔掉。
假如没有设置过滤规则,所有数据包都将装入内核缓冲区,并传递给用户层缓冲区。
1.libpcap安装在线安装
sudo apt-get install libpcap-dev
这些适宜有网路的同学
怎么难以安装尝试更新下源:
sudo apt-get update
离线编译安装
http://www.tcpdump.org/#latest-release
然后解压
tar zxvf libpcap-1.10.3.tar.gz
cd libpcap-1.10.3
./configure
sudo make
sudo make install
2.Libpcap的抓包流程:查找网路设备:目的是发觉可用的网卡,实现的函数为pcap_lookupdev(),假如当前有多个网卡,函数都会返回一个网路设备名的表针列表。打开网路设备:借助上一步中的返回值,可以决定使用那个网卡,通过函数pcap_open_live()打开网卡,返回用于捕捉网路数据包的秒数字。获得网路参数:这儿是借助函数pcap_lookupnet(),可以获得指定网路设备的IP地址和子网网段。编译过滤策略:Lipcap的主要功能就是提供数据包的过滤,函数pcap_compile()来实现。设置过滤器:在上一步的基础上借助pcap_setfilter()函数来设置。借助反弹函数,捕获数据包:函数pcap_loop()和pcap_dispatch()来抓去数据包,也可以借助函数pcap_next()和pcap_next_ex()来完成同样的工作。关掉网路设备:pcap_close()函数关系设备,释放资源。3.数据结构说明:
struct pcap_pkthdr {
struct timeval ts; /* time stamp */
bpf_u_int32 caplen; /* 抓到的数据包实际长度 */
bpf_u_int32 len; /*数据包的长度 */
};
4.libcap库函数
关于libcap的详尽讲解,后续会出文章,
本文只讲几个重要的函数。
打开网路插口
//这个函数会返回指定接口的pcap_t类型指针,后面的所有操作都要使用这个指针。
pcap_t * pcap_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf)
device:网络接口字符串,可以直接使用硬编码,比如eth0。
snaplen:对于每个数据包,从开头要抓多少个字节,我们可以设置这个值来只抓每个数据包的头部,
而不关心具体的内容。典型的以太网帧长度是1518字节,但其他的某些协议的数据包会更长一点,
但任何一个协议的一个数据包长度都必然小于65535个字节。
promisc:指定是否打开混杂模式(Promiscuous Mode),0表示非混杂模式,任何其他值表示混
合模式。如果要打开混杂模式,那么网卡必须也要打开混杂模式,可以使用如下的命令打开eth0
混杂模式:ifconfig eth0
to_ms:抓包时长单位为毫秒,0标示一直等待。
errbuf: 输出参数,打开网络接口失败原因。
打开离线的pcap文件
pcap_t * pcap_open_offline (const char *fname, char *errbuf)
fname :文件名称。
errbuf :打开失败的错误信息。
抓包函数
int pcap_loop(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
p: 打开的pcap_t类型指针。
cnt:一共抓多少个包,如果为负数就一直循环。
callback:回调函数指针
user:传递给回调函数的参数。
void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
userarg:是pcap_loop的最后一个参数,当收到足够数量的包后pcap_loop会调用callback回调函数,同时将pcap_loop()的user参数传递给它
pkthdr: 抓到的报文头信息。
packet:收到的包的数据。
过滤函数编译
int pcap_compile(pcap_t * p, struct bpf_program * fp, char * str, int optimize, bpf_u_int32 netmask)
//fp:这是一个传出参数,存放编译后的bpf
//str:过滤表达式
//optimize:是否需要优化过滤表达式
//metmask:简单设置为0即可
设置过滤函数
int pcap_setfilter(pcap_t * p, struct bpf_program * fp)
//参数fp就是pcap_compile()的第二个参数,存放编译后的bpf
释放网路插口
void pcap_close(pcap_t * p)
//该函数用于关闭pcap_open_live()获取的pcap_t的网络接口对象并释放相关资源。
打开网路包保存文件
pcap_dumper_t * pcap_dump_open (pcap_t *p, const char *fname)
//p:是我们已经打开的网络设备,从这个设备接收数据包。
// fname:是我们要写入的文件名,随便起。
//return: 如果出错,会返回NULL。可以借此检查这个文件有没有打开。
将网路包写入文件
void pcap_dump (u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
user:
就是文件描述符dumpfp,只不过要做一下类型转换。
由于这个函数一般在pcap_loop()的函数指针所指向的packet_handler中使用,
所以packet_handler中的user就是这里的user。
h:就是pkt_header
网路包文件关掉
pcap_dump_close(pcap_dumper_t * t);
5.libcap过滤规则
一些过滤表达式的事例如下:
src host 192.168.1.177
dst port 80
not tcp
tcp[13] == 0x02 and (dst port 22 or dst port 23)
icmp[icmptype] == icmp-echoreply or icmp[icmptype] == icmp-echo
ether dst 00:e0:09:c1:0e:82
只接收ip的ttl=5的数据包(ip首部开始的第8个字节)
ip[8] == 5
本例只抓取ip地址为本地IP的数据包,之后程序再对数据包合同头进行解析:
host 192.168.0.113
六、设计方案实现原理:
atach、cap进程运行在ubuntu中,要功击的目的终端可以使网路中任意设备,只须要能ping通即可。本例在windows上测试,采用桥接模式将ubuntu的网口和windows的网口桥接上去。
atach进程主要功能:
创建tcp套接字设置须要功击的终端的ip+port,之后执行connect函数connect成功,说明对方该端口可以使用更改port值,重复上面3个步骤
cap进程主要功能:
通过eth0,抓取指定规则:host192.168.0.116数据包解析出以太头、tcp头,ip头、tcp头,判定tcp头中sync+ack位为1的所有数据包复印出步骤2过滤下来的数据包代码流程:
七、测试1.环境:
windows ip:192.168.0.116
ubuntu ip:192.168.0.113
2.文件:
peng@ubuntu:~/work/test/pcap$ ls
atach header.c libpcap-1.10.3.tar.gz cap.c
cap libpcap-1.10.3 atach.c protocol.h
其中atach是上功击方,用于向指定ip发送sync包cap用于检查所有网卡收到的sync+ack数据包程序运行在ubuntu中。
3.启动网路调试助手
在windows上启动网路调试助手,
构建几个TcpServer,端标语分别为55、56、57
在这儿插入图片描述
4.启动程序1)首先启动cap
peng@ubuntu:~/work/test/pcap$ sudo ./cap 192.168.0.116
found device: eth0
netaddr:0000a8c0
try to open device eth0
filter:host 192.168.0.116
2)启动功击程序atach
须要新开启一个终端。
peng@ubuntu:~/work/test/pcap$ ./atach 192.168.0.116
5.运行截图如下:
一侧log可见,列列举了所有可以访问的端口,包括55、56、57。
注意:那种词组atach故意少了一个t,否则编译不过去:
你们可以试试大家的编译器,刑不刑!
八、代码
代码已然同步到gitee,地址如下:
https://gitee.com/yikoulinux/pcap.git
更多嵌入式、Linux、网络知识linux使用socket通信linux删除文件夹,后台留言加一口君好友!