JasonWang's Blog

从NAPI说一说Linux内核数据的接收流程

NAPI(New API)是Linux内核针对网络数据传输做出的一个优化措施,其目的是在高负载的大数据传输时,网络驱动收到硬件中断后,通过poll(轮询)方式将传输过来的数据包统一处理, 在poll时通过禁止网络设备中断以减少硬件中断数量(Interrupt Mitigation),从而实现更高的数据传输速率。

基于NAPI接口, 一般的网络传输(接收)有如下几个步骤:

  • 网络设备驱动加载与初始化(配置IP等)
  • 数据包从网络侧发送到网卡(Network Interface Controller, NIC)
  • 通过DMA(Direct Memory Access),将数据从网卡拷贝到内存的环形缓冲区(ring buffer)
  • 数据从网卡拷贝到内存后, NIC产生硬件中断告知内核有新的数据包达到
  • 内核收到中断后, 调用相应中断处理函数, 此时就会调用NAPI接口__napi_schedule开启poll线程(实际是触发一个软中断NET_RX_SOFTIRQ)(常规数据传输, 一般在处理NIC的中断时调用netif_rx_action处理网卡队列的数据)
  • ksoftirqd(每个CPU上都会启动一个软中断处理线程)收到软中断后被唤醒, 然后执行函数net_rx_action, 这个函数负责调用NAPI的poll接口来获取内存环形缓冲区的数据包
  • 解除网卡ring buffer中的DMA内存映射(unmapped), 数据由CPU负责处理, netif_receive_skb传递回内核协议栈
  • 如果内核支持数据包定向分发(packet steering)或者NIC本身支持多个接收队列的话, 从网卡过来的数据会在不同的CPU之间进行均衡, 这样可以获得更高的网络速率
  • 网络协议栈处理数据包,并将其发送到对应应用的socket接收缓冲区
利用SSH隧道访问局域网

SSH(Secure SHell)是一种基于加密算法的网络安全协议, 其在TCP/IP协议的基础上通过非对称公钥算法对用户身份进行验证. SSH在网络中有广泛的应用, 比如平常在远程登录时就会用到SSH, Github的代码仓库提交也会基于SSH协议来验证提交者的合法性, 而对常年生活在局域网内的人来说, SSH更多的用途则是搭建穿越防火墙的VPN实现网络自由.

一台服务器如果有公共域名或者IP地址, 只需要事先将客户端的公钥放到服务器上就可以正常登录, 但如果服务器本身位于防火墙之外(比如某个端口被禁)或者位于NAT(Network Address Translation)网关之后, 这个方法就不起作用了. 用过VPN的同志应该比较清楚, 穿透防火墙或者某个局域网的NAT网关, 一般要用到SSH隧道技术(SSH tunneling);SSH隧道技术也被称为端口转发(port forwarding).简单来说, 建立SSH隧道大致有两个流程:

聊一聊TCP协议

TCP(Transmission Control Protocol)即传输控制协议, 位于TCP/IP协议栈的第三层传输层, 与UDP不同的是, TCP号称提供有链接的(connection-oriented), 可靠的(reliable)字节流服务, 很多其他应用层协议如HTTP/SMTP/MQTT都是基于TCP协议实现.

这篇文章我们就从定义的角度来看一看TCP协议的具体工作原理. 首先看下有链接的(connection-oriented)具体含义.

TCP在发送数据之前, 第一件事情就是要在通信的双方建立一个通信的链路, 这个有点像日常生活中的打电话: A向B发起通话请求, B确认后双方建立通信链接才能正式通话. TCP也一样, 在发送任何数据之前必须要建立链接(connection), 这个建立通信链接的过程就是我们常说的”三次握手”;同样, 如果要想结束通信, 也需要有一个挥手的过程(四次挥手).有关TCP链接的建立与关闭可以参考之前的一篇文章(TCP的链接建立与状态迁移). 那么, TCP建立链接主要完成哪几件事情了?

TCP链接建立与状态迁移

学习TCP协议的第一步是要了解熟悉TCP的三次握手/四次挥手以及状态迁移图. 这篇文章用三个图展示TCP链接的建立与关闭以及状态的迁移.

TCP状态迁移

根据TCP协议的文档RFC793, 一个TCP链接有下图中的几个状态(图中实粗线为Client端的正常情况下状态迁移图, 虚线为Server端正常情况下的状态迁移图):

  • CLOSED: TCP链接的初始状态, 表示没有任何链接
  • LISTEN: (服务端)等待来自远程客户端的请求
  • SYN_SENT: 发送了一个建立TCP链接的SYN请求, 等待对端返回结果
  • SYN_RCVD: 收到了TCP建立链接的SYN包, 等待对方的回应(ACK)
  • ESTABLISHED: TCP链接建立成功, 从这里开始可以交换数据包了
  • FIN_WAIT1: 应用进程关闭了TCP链接(发送FIN包), 并等待对端的响应
  • FIN_WAIT2: 接收到关闭回应后, 等待对端结束TCP链接(等待FIN包)
  • CLOSING: 如果两端同时接收到了FIN包, 则进入该状态
  • CLOSE_WAIT:处于被动关闭一端接受到FIN请求后, 等待本地进程的关闭TCP链接
  • LAST_ACK: 服务端本地进程关闭TCP链接后, 发送FIN包, 等待回应
  • TIME_WAIT: 等待2*MSL(Maximum Segment Lifetime, TCP包的最大存活时间)后关闭该TCP链接, 等待足够长的时间是为了确保最后关闭链接的ACK包有足够长的时间达到对端, 如果对端未能收到该包, 则会重传FIN包, 这样对端也可以重传ACK包, 一般MSL为60s。有关更多TIME_WAIT状态的解释可以参考TIME-WAIT State.

TCP state transition

PPP拨号时拿到错误DNS的问题解析

最近碰到一个PPP拨号拿到了假的DNS地址10.11.12.13/14, 之前也发生过一次, 但是一直没有有效的日志, 所以就简单粗暴的做了一个方案: 在PPP拨号进行网络参数协商时, 如果发现拿到了10.11.12.13/14这样的DNS地址就修改为指定的运营商DNS地址. 本来以为万事大吉了, 没想到运营商DNS一改, 问题又暴露了, 好在重现抓到了现场日志, 终于找到了原因. 网上看有原来也有不少人碰到了类似现象(https://bugzilla.redhat.com/show_bug.cgi?id=467004#c31), 在这里简要的描述下整个问题的来龙去脉并给出几种可能的解决方案.

在介绍这个问题的根因之前, 先来了解下PPP协议的一些基本概念.

PPP协议介绍

PPP(Point-to-Point Protocol)是在SLIP(Serial Line Internet Protocol)的基础上发展而来, 其通过在终端与远端(remote peer)之间建立一个IPPP数据链路, 将终端设备接入网络. 早些年上网的时候, 把一个ADSL modem跟电脑连接后, 拿着运营商给的用户名与密码, 然后拨号接入互联网,这里边用到的协议就是PPP.

从HTTP到HTTPS

HTTP 自从上世纪90年代随着WEB的诞生而出现的,是所有WEB应用的基础。随着网络购物、电子商务、网上银行等逐渐普及,HTTP本身存在信息窃听与身份伪装等问题,已很难满足人们对于可信安全的通信环境的需求了。如何确保用户隐私与数据不被非法获取,这是HTTPS(HTTP Secure )需要解决的问题。使用HTTPS协议的网站,一般都以https开头而不是http,如:https://tools.ietf.org/html/rfc2246

那么,从数据安全的角度来看,HTTP有哪些不足了?

  • HTTP本身不具备加密功能,因此请求与响应都没有经过加密,而使用的是不加密的明文,因此内容可能会被窃听;
  • 通信时不会验证通信方(client/server)的身份,任何人都可以发送请求,而服务器对于所有请求也照单全收,因此客户端与服务端都有可能被伪装;
  • 在传输数据时,报文可能被篡改或者攻击,无法保证报文的完整性(integrity);这种在请求与数据传输过程中,被攻击者拦截并篡改的攻击方式被称为中间人攻击(Man-in-the-middle attack );
HTTP简介

HTTP(Hypertext Transfer Protocol)即超文本传输协议,是一种用于传输文本、音视频等超媒体(hypermedia)的应用层协议。HTTP从1990年开始就应用于WWW(World Wide Web)服务中,其发展变化与WEB服务紧密相连。这篇文章,就来看看HTTP协议的基本概念。

基本概念

HTTP协议允许不同类型的客户端与服务端进行通讯,支持不同的网络配置,并不依赖于特定的系统。在消息交换过程中,不保存任何状态(state-less,状态无关)。HTTP协议请求基于Request/Response,一个客户端向服务端发送request,该请求包含了Request Method, URL,协议版本以及请求的资源类型;服务端得到请求后,返回一个response,包括状态信息(协议版本,状态码)以及请求的资源。这样一次Request/Response的过程我们称为一次HTTP会话(session),大致有三个阶段:

  1. 客户端与服务端建立一个TCP链接;
  2. 客户端发送数据请求,等待回应;
  3. 服务端处理请求,返回结果并提供一个状态码与资源;
TCP/IP网络协议入门

互联网是由一个个电脑节点组成的网络,那么两个节点之间是如何进行数据通信的了?先来看一看一个最简单的通信模型:发送者通过一个媒介想一个接收者发送消息,同时接收者也可以向发送者发送消息。

这种通信模型与平时生活中的日常会话很是相似。A想与B交流,首先A与B要讲同样的方言,如果一个人讲湖南方言,而一个人讲粤语,则沟通无法进行, 除非请一个懂两种方言的翻译或者沟通双发统一使用某一种语言。抽象的来看,通信一般涉及到如下几个要素:

  • 两个需要通信的节点(地址);
  • 通信的数据交换协议(协议);
  • 节点之间的物理连接(媒介);