我在思考一个问题,希望各位能给我解答下。 有没有可能一个 http 的 response 数据过长,超过了单个 tcp 的 payload,然后被分割在多个 tcp 报文中? 如果是这样的话,假设被分割到两个 tcp 报文当中了,如何识别第二个报文的 payload 是 http 数据?(因为可能无法通过 HTTP / 1.1 识别了)
1
a7a2 2017-12-01 13:23:17 +08:00
你这个识别在 tcp 层面完成。。。
|
3
exch4nge 2017-12-01 13:25:05 +08:00
TCP 好像没有当个报文之类的一说吧,TCP 是个流,TCP 层下面的 IP 层会处理分包吧……
|
4
wcsjtu 2017-12-01 13:25:21 +08:00
这。。。。。
content-length 啊, 就算是 chunk 编码,也有终止符号。 应用层不用关心传输层的东西,不用管它分不分包 |
6
momocraft 2017-12-01 13:28:26 +08:00
1. 有
2. 从 tcp 读出来的只是字节流,看不到分几个包来的 |
7
3dwelcome 2017-12-01 13:28:42 +08:00
wireshark 里,tcp 分包识别,是通过包的序列号。比如第一个是 http,那么后边的 TCP 流就都是 http 协议的子包。
只通过中间一个 payload 识别格式,那是不可能的。 |
8
drzhaug OP @wcsjtu 你这么说我就懂了,我之前不知道怎么处理 chunk 编码的数据。 我试着用 libpcap 抓 http 包。不是在写应用层哈。。
|
10
rrfeng 2017-12-01 13:32:49 +08:00 via Android
TCP 分片、合并都在 TCP 层完成。
HTTP 不需要关心底层如何实现。HTTP 看到的就是完整的数据 |
11
3dwelcome 2017-12-01 13:34:28 +08:00
你单独捕获中间一个 payload 是没用的。
一般 HTTP 服务器都有 GZIP 压缩功能,TCP/HTTP 流只有从头到尾按序列号,把每个包组合到一起,才能解压获取完整内容。 |
12
cabing 2017-12-01 13:35:40 +08:00
这个就涉及到 tcp 的 TCP 粘包和拆包问题,要说的很多啊,你百度下就行 ^^
|
13
xiaxiaocao 2017-12-01 13:37:53 +08:00
你要写的是不是像我这个项目的东西:
https://github.com/hsiafan/httpparse |
15
Mutoo 2017-12-01 13:47:03 +08:00
wireshark 有一个 follow the tcp stream 的功能,是根据 ack 编号. TCP 严格按照顺序,所以没有其它需要顾虑的。
|
16
zhujinliang 2017-12-01 13:50:09 +08:00
一般防火墙或网监只做包识别,要是流的识别需要跟踪每个 TCP 连接,甚至需要缓存一段数据,开销太大
所以有的就故意在特征处断开,绕过检测 操作系统的话,由协议栈处理,每个连接都有对应的缓冲区,每个数据包到达后,由协议栈识别 IP、端口等,写入对应的缓冲区,对于程序来说,从缓冲区里读出来的是连续的 |
17
drzhaug OP @xiaxiaocao 我大概看了下,你的意思是抓取 http request 的 tcp 报文,然后模拟 tcp 请求,然后再处理返回的 response ?
|
18
ryd994 2017-12-01 13:59:55 +08:00
四元组
|
19
drzhaug OP @zhujinliang 没错,我尝试写一个抓取 http 的程序,就是在模拟一个协议栈,实验性的哈。
|
20
zhangysh1995 2017-12-01 14:10:52 +08:00
计算机网络没学好吧,网络层才分段的,Internet 的网络层就是 IP,这里才会把上层打包的内容分段。。。。
|
21
drzhaug OP @zhangysh1995 你没理解我说的意思 你说的东西太简单了
|
22
drzhaug OP @xiaxiaocao 谢谢,我刚刚没有太理解你的代码,我又看了一下,应该是我要的东西,我是想在 http 的基础上把图片截取出来。ps:我才知道 pcap 有 go 版本的,果断准备放弃 c 了。
|
23
zhangysh1995 2017-12-01 14:20:43 +08:00
@zhangysh1995 因为 IP 分段之后,到大主机会重新打包的。头部有 checksum 或者 length 这种参数,底层就处理了。不管里面存的是什么,是要长度不够就会拼起来。具体实现你要去看协议栈了,因为 HTTP 不管这些事情,它只管丢给传输层。建议重新看下计算机网络。
|
25
clino 2017-12-01 14:27:46 +08:00
建议楼主用 wireshark 抓个包然后看看协议分析以后的数据,估计能比较明了,ip/tcp/http 这几个层级的数据解析都能看到
|
26
drzhaug OP @zhangysh1995 好吧,我确实应该再看一下。但你能不能先告我一下我应该怎么做:我捕获的流过路由器上的 ethernet 帧,因该怎么处理才能获得完整的 http 响应数据的 body ?大概说一下就行,能理解的。谢谢
|
27
easing 2017-12-01 14:33:29 +08:00
用你问题里的例子,单纯看第二个 tcp 包是看不出来是不是 http payload 的,因为可能没有 http response header 字段供你判断,对 TCP 来说,它感知不了也不应该感知这是什么,那如何判断呢?只能在上层即 http 里,因为之前接收到了 response header,且有 content-length 信息,就会等待这么长的数据传上来,不管等多少个包,只要等够这么长了, 就算这个 http response 结束。
|
28
hcnhcn012 2017-12-01 14:39:17 +08:00 via iPhone
这个你不用担心,tcp 中的 ack 和 seq 字段一定会保证 tcp 数据段的有序的,超过了 MSS 就会拆包,不管里面包着的 http 怎么样,所以说这是面向 stream,而且 tcp 数据段不像 ip 数据包一样里面有个协议字段,也就是说 tcp 从来不知道数据部分封装的是个什么东西,也就是说在 tcp 层面无法识别 http
|
29
zhangysh1995 2017-12-01 14:45:08 +08:00
@drzhaug 我们一般的操作都是在自己的主机上进行的,用 Wireshark 可以完成,它也支持交换机或者路由器,可以参考这里 https://wiki.wireshark.org/CaptureSetup/Ethernet (全英文)。不过我觉得应该有更好的解决方案,这个就超出我的知识范围了,不好意思。
|
30
xiaxiaocao 2017-12-01 14:49:09 +08:00 1
@drzhaug 你这么说就明白多了,和我那个项目应该是同样功能。
主要是把 tcp 连接上的包重新组织好,然后就可以当作两个流来处理了,是不是 http 就通过开头的的内容可以判断。一个 http 内容读完之后如果下面的不是新的合法的 http 的 header 就放弃,当然这种情况基本不会出现。 |
32
gejigeji 2017-12-01 15:00:53 +08:00 3
所以应届生校招经常问七层网络协议的问题
|
33
neoblackcap 2017-12-01 15:07:36 +08:00
你就是要自己进行抓包对吧,在不用 libpcap 的情况下,那么说到底就是自己在用户空间重新实现 tcp/ip 协议栈,你具体可以参考 https://github.com/F-Stack/f-stack。
等你完成这个之后你就得到了一个你自己实现的 stock api,剩下的就是一般 http parser 的问题了,反正你得到了完整的 tcp 流了 |
34
Chingim 2017-12-01 16:07:16 +08:00 via Android
tcp 根本就不关心你 payload 不 payload。应用层给他什么他就传什么,如果包太大,它就拆了再传,到了目的地再把拆的包封好然后发给应用层。
如果你想了解如何拆装,那看 tcp 就好。 |
35
iceheart 2017-12-01 19:09:30 +08:00 via Android
看上去干的不是什么好事
|
36
cwek 2017-12-01 21:26:35 +08:00
TCP 会自动帮你拼合成连续的字节流送上应用层的,应用层感知不到。
|
39
dangyuluo 2017-12-02 01:11:46 +08:00
楼上说的很明白了,tcp 不管你的应用,你传多长的都行。他会根据自己的协议进行分包、合并、请求重发等。
|
41
msg7086 2017-12-02 03:40:42 +08:00
先搞明白网络分层问题。
物理层 绳子 链路层 以太网 网络层 IP 传输层 TCP 应用层 HTTP 上层是 HTTP 数据,到了下层 TCP 的时候,几乎一定是会拆包的。 通常 TCP 包不到 2KB,你有多少 HTTP 流量是前后加起来少于 2KB 的。 如果你能拿到所有的 TCP 豹纹,那就按照 TCP 协议拆包解码成流就行了。 根据 IP 和端口找到对应的 TCP Session,排好序以后拆包得到完整的流就行了。 如果只能偶尔拿到一两个包,那是没法直接判断 HTTP 请求的,最多靠猜。 |
43
fivestrong 2017-12-02 09:54:19 +08:00 via Android
go 语言有个 google 提供的 gopacket 包,里面有一些 tcp 流重装的例子,我之前也想抓包获取 http 请求的内容,可惜学艺不精,只能找到 ip 端口,再往下就不知道怎么解析 http 数据了。
|
44
cy18 2017-12-02 10:19:02 +08:00 via Android
@zhujinliang 现在 sni 代理好像被认证了,没法用。能不能用这个思路在适当的地方把 TCP 包截断从而避开 sni 被认证的问题?感觉大墙可能还没有做到跟踪每一个 TCP 链接。
|
45
q397064399 2017-12-02 17:20:25 +08:00
流..
|