在编写TCP程序的时候,对于服务端,accept成功返回的时候,就一定意味着某个客户端已经成功建立了TCP连接吗?对于客户端,connect成功返回就一定意味着自己成功连接上服务端了么?远远不是!
accept/connect这两个socket调用完全是基于TCP三次握手状态机的,即只要本地TCP状态机进入ESTABLISH状态,就会成功返
回。而我们知道,TCP的三次握手本身就是一次权衡的结果。为什么不是四次握手呢?为什么不是五次呢?...问题可以一直这么问下去。
事实上,客户端完全可以在收到syn-ack之后,发送最后一个ack之后不辞而别,服务端也可以在收到syn之后,发送syn-ack之后不辞而别,从
此再也不问世事,对于对端而言,accept/connect显然会成功返回,因为对端的状态机已经转换到了ESTABLISH,它们无法意识到自己被耍
弄了。对于TCP而言,它作为一个基于连接的端到端协议,和我们的工作很类似,入职的时候,要签订合同,离职的时候,要办理离职手续,对于不辞而别者,你
能做的大多数只能是嘲讽。可是对于TCP而言,却可以用上述这种不辞而别手段来提高自己的“每秒新建连接数”用来欺骗比较低级的测试工具,或者嘲弄那些知
其然不知其所以然的应聘者(作为一块有效的试金石,有时真的要问那些应聘者一些这类问题,它们要比让应聘者写个握手过程,写个socket程序,解释一下
socket函数的参数要有效的多)。
对于上述的不辞而别,欺骗客户端要比欺骗服务端更加容易,因为对于服务端而言,存在一个socket
option,叫做TCP_DEFER_ACCEPT,它在收到客户端的第一笔数据之前,抑制accept的返回,当然,它仅仅针对客户端首先发送第一笔
数据的应用层协议(比如HTTP协议)有效。
如果是我在考察应聘者对TCP编程的理解,我会让他们写一个或者理解一个全程的欺骗程序,将TCP的连接ack机制转换为挑战/应答模式:
欺
骗客户端:编写一个欺骗服务端,持续执行且仅仅执行下面的逻辑:1.只要收到syn,就计算一个初始序列号,构造并回复syn-ack;2.只要收到数
据,就基于这段数据的TCP头信息构造纯ack包回应之;3.只要收到fin,自己就ack掉它,然后也发一个fin;4.自己决不主动发起任何数据。
欺骗服务端:这个也不难...
至
于如何拿到TCP数据而不是让其进入协议栈,这在实现上是重要的,可以考察应聘者对系统的熟悉程度。为何不能进入协议栈呢?因为进入协议栈就将进入标准的
正确的处理流程,一般会被RST...那么如何拿到数据呢?办法太多了,包括但不限于:1.使用PACKET套接字;2.使用PF_RING;3.使用
TUN/TAP网卡;4.使用Netfilter queue机制;5.直接改内核...
以上的那些工作真的有意义吗?常规地讲,没有任何意义,即便你通过这种方式使自己的服务器达到了超极高的并发,一旦被发现,估计就不仅仅是技术范畴的问题
的。事实上,做上面的事的意义在于,至此你将明白什么是“一个TCP连接”,确切地说,一个TCP连接包括两个无误的状态机,而不仅仅是一个,一个TCP
连接在概念上和网络没有任何关系,是以为“端到端协议”,对于上述的行为,显然在不辞而别或者挑战应答的那一端没有维护一个无误的状态机,所以就不是一个
完整无误的TCP连接,基于TCP连接的性能测试比如新建TCP连接数测试就必须可以检测到这种情况。所以说,这种测试必须包含业务范畴的挑战/应答数据
的传输,即,再次重申:你可以telnet成功某个IP的某个端口,并不意味着一定有某个服务在为你开启。换句话说,只要能拿到数据包,怎么处理就是自己
的事了,如果在对端看来你看起来像个正常的协议栈,你就可以欺骗他们了,处在两地的两个端作为一个整体缺乏一种集体自省机制...
缺乏自省机制是必然的,因为一旦有了自省机制,那么网络就真的变成了智能生物...计算机拥有处理任意复杂数据的能力,遗憾的是,它自己并不知道自己有这
种能力。深入思考这个问题是有意思的,我知道我姓赵,但是我自己知道“我我知道我姓赵”这件事吗?“我最害怕天黑”和“我承认我最害怕天黑”是完全不同
的。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。