PROC文件tcp_challenge_ack_limit控制每秒钟发送挑战ACK报文的数量。避免遭受Blind In-Window Attacks,包括reset,sync或者数据注入攻击等,详解RFC5961。

初始化

在TCP协议初始化函数tcp_sk_init中赋值为1000。通过PROC文件tcp_challenge_ack_limit可查看此值,并可进行修改。

static int __net_init tcp_sk_init(struct net *net)
{/* rfc5961 challenge ack rate limiting */net->ipv4.sysctl_tcp_challenge_ack_limit = 1000;
}
$ cat /proc/sys/net/ipv4/tcp_challenge_ack_limit
1000

挑战ACK发送控制

核心函数tcp_send_challenge_ack如下。如果挑战ACK报文要能够发送,必须首先满足tcp_invalid_ratelimit变量定义的时间间隔,默认为HZ的一半即500毫秒。详情参见:https://blog.csdn.net/sinat_20184565/article/details/89481607。

算法如下:在首次进入此函数时,挑战时间戳和挑战次数都为空,获取到当前的时间(now的单位秒),此时now必定不等于挑战时间戳,将挑战次数初始化为tcp_challenge_ack_limit设定值的一半,与零至tcp_challenge_ack_limit值之间的随机值的和,并且初始化挑战时间戳。之后,如果再次进入函数时,当前时间还在同一秒内,判断挑战次数是否为零,不成立递减挑战次数,发送挑战ACK报文。

如果再次进入函数时,当前时间已经进入下一秒,重新初始化挑战次数challenge_count和挑战时间戳challenge_timestamp。在同一秒钟内,已经发送了超过挑战次数的ACK报文后,不在发送挑战ACK报文。

/* RFC 5961 7 [ACK Throttling] */
static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb)
{static u32 challenge_timestamp;static unsigned int challenge_count;/* First check our per-socket dupack rate limit. */if (__tcp_oow_rate_limited(net, LINUX_MIB_TCPACKSKIPPEDCHALLENGE, &tp->last_oow_ack_time))return;/* Then check host-wide RFC 5961 rate limit. */now = jiffies / HZ;if (now != challenge_timestamp) {u32 ack_limit = net->ipv4.sysctl_tcp_challenge_ack_limit;u32 half = (ack_limit + 1) >> 1;challenge_timestamp = now;WRITE_ONCE(challenge_count, half + prandom_u32_max(ack_limit));}count = READ_ONCE(challenge_count);if (count > 0) {WRITE_ONCE(challenge_count, count - 1);NET_INC_STATS(net, LINUX_MIB_TCPCHALLENGEACK);tcp_send_ack(sk);}
}

数据注入攻击

如果接收报文的确认序号小于本地套接口待确认序号,表明为一个已经确认过的序号,并且其确认序号在套接口当前待确认序号减去本地发送窗口之前,内核认为此报文很可能并非对端发送,即其为攻击者构造出来的报文,合法的报文确认序号ACK的范围:((SND.UNA - MAX.SND.WND) <= SEG.ACK <= SND.NXT)。否则,不在此范围内认为是盲数据注入攻击Blind Data Injection Attack。但是,有可能并非攻击者发送,而是来自对端的报文,此时回复挑战ACK报文,使对端有机会修正其确认序号ACK。

按照RFC5961的描述,为应对数据注入攻击,进一步缩小合法确认序号ACK的范围,要求报文中的确认序号大于套接口第一个待确认序号。合法的报文确认序号范围:(SND.UNA <= SEG.ACK <= SND.NXT)。内核不处理无效确认序号的报文,避免注入非法数据。

static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
{u32 prior_snd_una = tp->snd_una;/* If the ack is older than previous acks then we can probably ignore it. */if (before(ack, prior_snd_una)) {/* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */if (before(ack, prior_snd_una - tp->max_window)) {if (!(flag & FLAG_NO_CHALLENGE_ACK))tcp_send_challenge_ack(sk, skb);return -1;}goto old_ack;}if (after(ack, tp->snd_nxt))goto invalid_ack;old_ack:SOCK_DEBUG(sk, "Ack %u before %u:%u\n", ack, tp->snd_una, tp->snd_nxt);return 0;
}

复位RST攻击

如下的TCP报文检查函数tcp_validate_incoming。
为应对攻击者伪造的RST报文,对于TCP头部标志设置了reset位的报文,仅当其序号等于本端套接口待接收的序号时(增加攻击者猜测的序号的难度),或者tcp_reset_check函数结果为真时(其判读RST是否紧随之前的一个FIN报文),本端才可复位此连接。另外一种情况是,当启用SACK时,仅当报文序号等于所有SACK块中最大的数据序号时,本端可复位此连接。

以上条件都不成立,内核认为不合法的RST报文或者为恶意的RST攻击,回应挑战ACK报文,以使得发送不合法报文的对端得以恢复。

static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, const struct tcphdr *th, int syn_inerr)
{/* Step 2: check RST bit */if (th->rst) {if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt || tcp_reset_check(sk, skb)) {rst_seq_match = true;} else if (tcp_is_sack(tp) && tp->rx_opt.num_sacks > 0) {struct tcp_sack_block *sp = &tp->selective_acks[0];int max_sack = sp[0].end_seq;for (this_sack = 1; this_sack < tp->rx_opt.num_sacks; ++this_sack) {max_sack = after(sp[this_sack].end_seq, max_sack) ? sp[this_sack].end_seq : max_sack;}if (TCP_SKB_CB(skb)->seq == max_sack)rst_seq_match = true;}if (rst_seq_match)tcp_reset(sk);else {/* Disable TFO if RST is out-of-order and no data has been received for current active TFO socket */if (tp->syn_fastopen && !tp->data_segs_in && sk->sk_state == TCP_ESTABLISHED)tcp_fastopen_active_disable(sk);tcp_send_challenge_ack(sk, skb);}goto discard;}
}

如果RST报文的序号不等于套接口的待接收序号,当时等于待接收序号减一,并且套接口之前接收到了FIN报文,对于主动关闭端,接收到FIN报文之后将进入TCPF_CLOSING状态。对于被动关闭端,接收到FIN报文之后,进入TCPF_CLOSE_WAIT状态,在套接口close之后,转换到TCPF_LAST_ACK状态。

根据内核的注释,对于Mac OSX系统中意外结束的TCP连接(Ctrl+C),OSX将接连发送FIN和RST报文,并且RST报文的序号等于之前的FIN报文序号。

static bool tcp_reset_check(const struct sock *sk, const struct sk_buff *skb)
{struct tcp_sock *tp = tcp_sk(sk);return unlikely(TCP_SKB_CB(skb)->seq == (tp->rcv_nxt - 1) &&(1 << sk->sk_state) & (TCPF_CLOSE_WAIT | TCPF_LAST_ACK | TCPF_CLOSING));
}

SYN攻击

对于处在连接阶段的TCP连接,未避免攻击者伪造SYN报文导致接收端误以为对端连接已关闭,需要重新建立而导致的RST报文发送问题,内核改为对接收到的SYN报文不管其序号是否合法,仅回复挑战ACK报文,内容如下:<SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>。如果对端确实要重新开始新的连接,在接收到挑战ACK报文之后,可根据其中的确认序号构造一个合法的RST报文先关闭之前的连接。如此处理,攻击者伪造的SYN报文将不能够复位存在的链接了。

static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, const struct tcphdr *th, int syn_inerr)
{/* Step 1: check sequence number */if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {if (!th->rst) {if (th->syn)goto syn_challenge;goto discard;}/* step 4: Check for a SYN。 RFC 5961 4.2 : Send a challenge ack */if (th->syn) {
syn_challenge:tcp_send_challenge_ack(sk, skb);goto discard;}
}

以上处理,有一个小的弊端,当对端意外重启之后,如果使用相同的TCP的IP地址和端口号重新发起连接,发送SYN报文,并且,其初始序号选择了RCV.NXT-1的值,加入本端的连接还在,等接收到此SYN报文时,将回复挑战ACK报文,其确认序号为RCV.NXT,但是当对端接收到此挑战ACK报文,因为其正好确认了之前发送的SYN报文,对端并不会发送RST报文结束重启之前的连接。导致新连接一直建立不起来,要等到SYN报文超时。不过这属于非常极端情况。

内核版本 4.15

TCP挑战ACK报文限速相关推荐

  1. TCP协议之《ACK报文限速》

    PROC文件tcp_challenge_ack_limit控制每秒钟发送挑战ACK报文的数量.避免遭受Blind In-Window Attacks,包括reset,sync或者数据注入攻击等,详解R ...

  2. TCP报文( tcp dup ack 、TCP Retransmission)

    最近因使用FTP 上传数据的时候总是不能成功,抓包后发现 TCP 报文出现 TCP dup ack 与 TCP Retransmission 两种类型的包.收集整理下 TCP dup ack (重复应 ...

  3. TCP报文之-tcp dup ack 、tcp Out-of-Order

    使用WireShark抓包,选择TCP报文,TCP是一种安全的协议,在网络出现状况时也能安全稳定的传输数据,但是在网络出现问题时tcp报文中会有很多中情况导致报文重传或者是重组.现在就在报文中遇到的几 ...

  4. 简述tcp协议三报文握手过程_华为原理 | 传输层协议amp;交换转发原理

    Interface GigabitEthernet0/0/0 ip address 12.1.1.2 255.255.255.0 arp-proxy enable \\华为接口下默认没有开启代理ARP ...

  5. 简述tcp协议三报文握手过程_TCP协议中的三次握手和四次挥手(图解)

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资 ...

  6. 【学习笔记】传输层:TCP协议(报文段、连接管理{握手}、可靠传输、流量控制、拥塞控制)

    文章目录 一. 协议特点 & 报文段 ① 特点 ② 报文段首部格式 二. TCP连接管理 ① 建立联系(三次握手) SYN洪泛攻击 ② 连接释放(四次挥手) 三. TCP流量控制 ① 序号 ② ...

  7. 关于抓包出现TCP DUP ACK问题

    最近在跟一个CDN服务器端做对接,从CDN服务器下载内容(http),发现抓包出现非常多的Tcp Dup Ac​k异常提示.通过查阅质料得知Tcp Dup Ack xxx#y 代表了数据段丢失TCP状 ...

  8. 虚拟网络运维----基于wireshark报文分析快速过滤(tcp,icmp,http)报文时延

    文章目录 虚拟网络运维----基于wireshark报文分析快速过滤(tcp,icmp,http)报文时延 前言 tcp协议高时延报文定位 http协议高时延报文定位 icmp协议高时延报文 虚拟网络 ...

  9. TCP Dup ACK xxx#x分析

    TCP Dup ACK xxx#x分析 wireshark报文出现TCP Dup ACK xxx#x时,代表了数据段丢失 TCP 状态,xxx 代表数据丢失的位置(即wireshark报文显示界面最左 ...

最新文章

  1. css颜色rgba代码对照表_改善 CSS 的 10 个最佳实践
  2. setAdapter(adapter)空指针nullPointer 解决办法
  3. 【学习总结】GirlsInAI ML-diary day-3-数据类型
  4. 1107 Social Clusters (30 分)【难度: 中 / 知识点: 并查集】
  5. Deeplearning:windows多版本cuda安装、管理
  6. jq校验输入框值变化时_谈谈自己对CRC校验的理解
  7. python 3.6.5编译安装_Linux系统安装Python3.6.5
  8. 正则表达式实现身份证信息验证
  9. 在pytorch中expand_dim
  10. 单机到集群的WEB架构演变
  11. linux rtl8188eu ap模式 密码错误 disassoc reason code(8)
  12. 2019年1024,deepin安装原生Linux QQ
  13. Windows 下载安装 SonarQube和使用
  14. 叉积(向量积、外积)的运算法则及其与点积(数量积、内积)的混合运算
  15. win10打开谷歌浏览器chrome,并进入kiosk模式
  16. uni-app 兼容不同平台
  17. SUSE Linux配置xmanager5
  18. gpd计算机等级,GPD 文件扩展名: 它是什么以及如何打开它?
  19. 2022-07-10 第四小组 孙翰章 CSS学习笔记
  20. 小 H 的数字c++

热门文章

  1. C++ rapidjson 使用
  2. 全网最全-HR面试高频问题-求职宝典
  3. 计算机二级不看教材只刷题可以吗,初级会计备考只刷题不买教材行不行?可以通过吗?...
  4. 银行风险预警系统建设中对Java规则引擎选型推荐
  5. 高通gobi系列modem
  6. 元宇宙中的法律与自我监管
  7. 右侧交易-辨别买卖点
  8. Git-gitignore规则之“感叹号“的用法坑点
  9. 基于微信小程序的汽车买卖系统设计与实现.rar(项目源码+论文)
  10. 设计模式-Visitor模式(访问者模式)