如何使用iptables防火墙模拟远程服务超时

如何,使用,iptables,防火墙,模拟,远程,服务,超时 · 浏览次数 : 202

小编点评

**概述** 本文模拟了服务A返回数据超时的情况,通过设置超时时间,避免了程序阻塞和线程 hang住。 **步骤** 1. **iptables 安装和启动** - 使用 `iptables -I INPUT -p tcp -m tcp --dport 8084 -j ACCEPT` 命令安装和启动 iptables。 - 确保 `iptables` 进程已经处于运行状态。 2. **模拟超时** - 使用 `python -m SimpleHTTPServer 8000` 启动一个简单的 HTTP 服务。 - 请求该端口的接口,并记录请求结果。 3. **分析超时原因** - 观察 `iptables` 的日志,查看 `DROP` 记录。 - 确认服务A返回的数据包的 TCP 标志没有设置超时时间。 4. **设置超时时间** - 修改 `SimpleHTTPServer` 的代码设置超时时间。 - 使用 `iptables -I INPUT -p tcp -m tcp --dport 8084 -j DROP` 设置超时时间。 5. **再次请求并观察结果** - 请求服务A的接口,记录请求结果。 - 观察服务端日志,确认超时消息。 **结论** 通过设置超时时间,成功模拟了服务A返回数据超时的情况,避免了程序阻塞和线程 hang住。

正文

前言

超时,应该是程序员很不爱处理的一种状态。当我们调用某服务、某个中间件、db时,希望对方能快速回复,正确就正常,错误就错误,而不是一直不回复。目前在后端领域来说,如java领域,调用服务时以同步阻塞调用为主,此时一般会阻塞当前线程,等待结果。如果我们设置了超时时间还好,一段时间等不到就报错了,要是超时时间没设置或者过长,会导致线程动不了,即hang住了,多来几个这种线程,线程池也就全都hang住了,此时,我们也就没办法响应前端了。

由于业务代码或者底层框架编码时不注意超时问题,这个问题经常会在线上才出现(比如依赖的某个服务A,长时间运行的情况下,会出现响应慢问题,但是在平时开发环境服务A经常重启,把问题掩盖了,我们依赖方在开发环境测,当然也就没注意A可能超时,等已上线,A一超时,我们就完蛋了)。

我前面几篇文章的起源,也就是研究线上一个问题,就是怀疑我们服务中的数据库连接池的连接被db或者防火墙干掉了,导致我们这边因为也没设置超时时间,进而卡死。

当时我就想模拟oracle数据库不响应的情况,发现还是很不好模拟,后面经过各种查资料,才发现现在使用的这种iptables防火墙丢弃oracle返回的数据包的方式。

实验环境

我们要模拟的事情如下:

image-20230729212918357

oracle我就不模拟了,原理一样的,那个网络包要复杂一些,讲起来就重点发散了。

这个图里,服务A就是相当于oracle,我们这里是简单启动一个http服务:

python -m SimpleHTTPServer 8000

我们直接请求看下结果:

image-20230729213214486

然后,我们后台服务部署在10.80.121.46服务器的8084端口,我们正常请求该端口的接口,它就会去请求服务A,将服务A的响应返回给我们。

@PostMapping("/")
@ApiOperation(value = "访问远程服务")
public String test() {
    String s = HttpClientUtil.doGet("http://10.80.121.115:8000/");
    log.info("resp:{}",s);
    return s;
}

image-20230729213440371

实验步骤

iptables安装启动

yum install -y iptables-services

systemctl start iptables
systemctl stop iptables
systemctl status iptables
如果提示绿色的“active (exited)”,则iptables已经启动成功。

允许浏览器访问8084端口

允许访问服务端口,否则没法测试,另外,如果对iptables完全不懂的,先去看下我前一篇再回来看。

iptables -I INPUT -p tcp -m tcp --dport 8084 -j ACCEPT

思路

要模拟出服务A不返回数据的效果,其实有两种思路,一种是,把我们程序发给服务A的包丢掉;一种是,不丢弃我们发出去的包,但是,把服务A回给我们的包丢掉。

思路2:丢弃服务A返回的数据包

我是一开始就用的这个思路,所以先讲这种。

这种的话,有的人可能觉得很简单,实际上不是那么简单。我们不能简单地把服务A返回给我们的包,全丢,因为这样的话,tcp连接都没法建立。所以,我们要丢服务A返回的数据包,但是,tcp三次握手的包不能丢。

我们来分析下,这两种包的不同之处。

三次握手时,对方返回的包长这样:

image-20230729214357116

即,tcp标志位设置了SYN/ACK。

再来看看返回数据时的报文:

image-20230729214524226

可以看到,标志不一样,这次是PSH/ACK。

所以,我们可以根据标志来进行区分。

所以,最终我们的丢包策略是:

iptables -I INPUT 1 -p tcp -m tcp  --tcp-flags PSH,ACK PSH,ACK --sport 8000 -j DROP

上面的意思是,对于服务A返回的包(源端口--sport为8000),如果tcp标志为--tcp-flags PSH,ACK PSH,ACK,就drop

这个tcp-flags的语法,详细如下:

[!] --tcp-flags mask comp
              Match when the TCP flags are as specified.  The first argument mask is the flags which we should examine, written as a comma-separated  list,  and  the
              second argument comp is a comma-separated list of flags which must be set.  Flags are: SYN ACK FIN RST URG PSH ALL NONE.  Hence the command
               iptables -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST SYN
              will only match packets with the SYN flag set, and the ACK, FIN and RST flags unset.

后面接了两端,第一段是掩码,表示要检查哪些标志位(这里指定n个要检查的标志位,别的没说要检查的,咱们就不管了),第二段是我们预期应该要设置的标志,比如,我们这里预期是要设置了PSH和ACK的才算匹配。

ok,加完这个,我们再请求一次,看看效果,我们看前台是转圈,后台日志呢,是过了很久之后,显示超时:

image-20230729215400867

然后,我在后台服务机器抓了包,可以看到,下面全是超时重传,因为服务A的数据发过来,我们丢弃了,服务A以为我们没收到,一直重发:

image-20230729215553769

而我们服务这边,代码也是有点问题的,超时时间用的默认的,没设置:

image-20230729215733831

过了很久,都快3分钟了,一直等不到回应,才去断开连接,这要是在线上,不是又悲剧了吗?所以,这个模拟超时,还是可以找出一些我们代码问题的,有点用。

另外,我们看到,对方还给我们回复了RST,我之前遇到过一种情况,对方回复RST后,我们这边连接就断开了,报错是:broken pipe,而不是read time out,如果,我们必须要模拟出read time out这种异常的话,可以把对方的RST也给丢了。

iptables -I INPUT 1 -p tcp -m tcp  --tcp-flags RST RST --sport 8000 -j DROP

思路1:丢弃我们发出去的包

这个思路呢,和上面的原理类似,也是看看我们要发出去的包有什么特征,然后识别出来丢弃。

我最终写出来的规则如下:

iptables -I OUTPUT 1 -p tcp -m tcp  --tcp-flags PSH,ACK PSH,ACK --dport 8000 -j DROP

首先,这个是出去的包,所以,-I OUTPUT表示把规则写入OUTPUT链,然后tcp标志和上面是一样的(这个需要自己结合tcpdump去观察这些标志),然后目的端口是8000,这样的包,就是我们程序发出去的包,丢弃。

另外,我也观察了tcpdump抓包,这次,意外的是:

image-20230729220937910

整个过程,在tcpdump看来,只发现有三次握手的包,而程序发出去的包,被iptables丢弃后直接没进协议栈,压根就没再继续了,所以tcpdump也就看不到。

这个思路看起来更简单暴力一些。

最终的效果还是一样的:

image-20230729221133848

结语

整个过程就讲完了,iptables暂时告一段落,最近要忙点其他的事情了。

与如何使用iptables防火墙模拟远程服务超时相似的内容:

如何使用iptables防火墙模拟远程服务超时

# 前言 超时,应该是程序员很不爱处理的一种状态。当我们调用某服务、某个中间件、db时,希望对方能快速回复,正确就正常,错误就错误,而不是一直不回复。目前在后端领域来说,如java领域,调用服务时以同步阻塞调用为主,此时一般会阻塞当前线程,等待结果。如果我们设置了超时时间还好,一段时间等不到就报错了

[转帖]Linux 防火墙开放特定端口 (iptables)

查看状态: iptables -L -n 下面添加对特定端口开放的方法: 使用iptables开放如下端口 /sbin/iptables -I INPUT -p tcp --dport 8000 -j ACCEPT 保存 /etc/rc.d/init.d/iptables save 重启服务 ser

[转帖]Linux 防火墙开放特定端口 (iptables)

查看状态: iptables -L -n 下面添加对特定端口开放的方法: 使用iptables开放如下端口 /sbin/iptables -I INPUT -p tcp --dport 8000 -j ACCEPT 保存 /etc/rc.d/init.d/iptables save 重启服务 ser

[转帖]Linux下使用 ipset 封大量IP及ipset参数说明

https://www.cnblogs.com/xiaofeng666/p/10952627.html Linux使用iptables封IP,是常用的应对网络攻击的方法,但要封禁成千上万个IP,如果添加成千上万条规则,对机器性能影响较大,使用ipset能解决这个问题。 iptables 包含几个表,

[转帖]ipset命令介绍与基本使用

一. 介绍 ipset命令是用于管理内核中IP sets模块的,如iptables之于netfilter。ipset字面意思是一些IP地址组成一个集合(set)。但是ipset用于用于存储IP地址,整个子网,端口号(TCP/UDP),MAC地址,网络接口名或者上述这些的组合。ipset主要是由ipt

如何使用csproj构建C#源代码组件NuGet包?

一般我们构建传统的NuGet包,都是打包和分发dll程序集文件。 至于打包和分发C#源代码文件的做法,比较少见。 那么这种打包源代码文件的做法,有什么优点和缺点呢? 优点: 方便阅读源代码。 方便断点调试。 减少 Assembly 程序集模块加载个数。 更利于发布期间的剪裁(PublishTrimm

如何使用JavaScript实现在线Excel附件的上传与下载?

前言 在本地使用Excel时,经常会有需要在Excel中添加一些附件文件的需求,例如在Excel中附带一些Word,CAD图等等。同样的,类比到Web端,现在很多人用的在线Excel是否也可以像本地一样实现附件文件的操作呢?答案是肯定的,不过和本地不同的是,Web端不会直接打开附件,而是使用超链接单

如何使用前端表格控件实现数据更新?

前言 小编之前分享过一篇文章叫《如何使用前端表格控件实现多数据源整合?》。今天,继续为大家介绍如何使用前端表格控件来更新已连接的数据源信息。 环境准备 SpreadJS在线表格编辑器: SpreadJS 前端表格控件新版本新增了一款报表插件,该插件基于 SpreadJS 本身强大的表格能力,在 Da

如何使用Node.js、TypeScript和Express实现RESTful API服务

Node.js是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。Express是一个保持最小规模的灵活的 Node.js Web应用程序开发框架,为Web和移动应用程序提供一组强大的功能。使用Node

如何使用前端表格控件实现多数据源整合?

前言 作为表格产品的典型应用场景之一,几乎所有的行业都会存在类 Excel 报表开发这样的应用场景,而在这些应用场景中,经常会遇见下面的这些痛点: 报表数据往往来自多个不同的数据源,需要报表系统能够同时连接多个数据源,并融合不同的数据格式 实际的报表中需要对数据结果进行逻辑计算,例如销售的环比和同比