首页 > 系统相关 >iptables简要介绍及使用iptables实践NAT技术

iptables简要介绍及使用iptables实践NAT技术

时间:2023-07-24 09:11:47浏览次数:44  
标签:iptables 简要 8080 tcp hook PREROUTING NAT 规则

简介

iptables的文章多如牛毛,但是,我读了一些,发现虽然成体系,但是不便理解,今天就结合自己的理解,好好讲解下,另外,我们也会使用iptables来实验一个nat地址转换的demo,nat转换,通俗地讲,一般是为了解决ipv4公网地址不够用的问题,因此在学校、公司等机构的有公网ip的服务器上,部署nat软件进行地址转换,如内网机器访问互联网时,将源地址转换为服务器的公网ip;在收到响应时,此时目的地址是公网ip,此时需要修改为内网机器的地址。

这个东西,教科书里学了很多年了,没想到还能走进现实,也是有点意思。

iptables和netfilter的关系

iptables运行在用户态,netfilter运行在linux内核中。iptables相当于一套界面,可以将防火墙规则写入内核中的一片内存区域,而netfilter会去读取这片内存区域中的规则,根据规则进行对应的网络包处理,如丢弃、放行等。

正因为如此,我们需要手动安装iptables,如yum install -y iptables-services,但是,netfilter是linux内核本身自带的,无需安装。

简单来说,netfilter才是核心,你要觉得iptables不好用,可以换其他的命令行、图形界面工具,甚至自己写也可以。当然,netfilter和iptables都是同一个团队弄的,因为它不可能让大家直接写代码去操作netfilter,肯定还是得搞个好用的命令行工具给大家用吧,所以有了iptables。

而且,现在团队觉得iptables还是不够好,目前新搞了个nftables来取代iptables。

项目官网:https://www.netfilter.org/index.html

网络包的流向

大概有这么几种网络包:

  • 从网卡进来,但是目的地址不是当前机器(如当前机器仅负责路由转发、防火墙等),此时,不需要交给本机进程处理,直接按照路由表转发出去
  • 从网卡进来,目的地址是当前机器,此时,会交给本机的进程处理(如tcp的话,会根据端口号找到对应进程)
  • 本机要向外发送的数据库包,不管是请求其他远程服务(此时作为客户端,会主动向外发包),或者是本机作为服务器,对外部进来的请求包做出回应。这两种,都算是要出去的包

如果让你来设计,你应该也会引入几个时间点,在这个时间点,主动去查询用户定义的规则,看看规则中是要丢弃还是放行数据包。

时间点的考虑,也很重要。

比如,针对网卡收到的数据包的处理,第一个时间点,应该是在检查路由表之前(即检查目的地址是否是本机之前),此时,给用户提供一个介入的时机,用户甚至可以修改这个数据包,比如,本来是发给当前机器的,我可以将目的地址改为其他机器,这就是DNAT(nat分为修改源地址和目的地址,这里说的这种,就是修改目的地址)适用的场景;

第二个时间点,应该是在路由决定做出之后,在交给进程处理之前;

第三个时间点,应该是进程处理完成后,假如需要回应,即进程将数据包交给我们后,此时也可以进行处理

另外,针对那种路由转发的数据,在转发出去之前,应该也可以进行一些处理。

这些时间点呢,一般就是扩展点,就像spring里面一样,bean的创建过程中有很多时间点会回调用户的函数,用户就可以注册自己的回调函数,进行一些特殊的逻辑处理。

netfilter中的扩展点

Netfifilter一共在内核的网络协议栈中,插入了5个扩展点(官网叫hook)。我参考了如下文章:

https://www.usenix.org/system/files/login/articles/892-neira.pdf

  • PREROUTING:

    All the packets, with no exceptions, hit this hook, which is reached before the routing decision。

    Port Address Translation (NAPT) and Redirections, that is, Destination Network Translation (DNAT), are implemented in this hook.

​ 这个时间点,就是所有的网络包在做出路由决定前,就会调用本hook。一般来说,端口转换和重定向、DNAT(目标地址转换)就是在这里实现

  • LOCAL INPUT:

    All the packets going to the local machine reach this hook. This is the last hook in the incoming path for the local machine traffific.

​ 在检查目的地址后,发现包是发给本机的,那么这些包在交给进程之前,就会调用本hook。

  • FORWARD:

    Packets not going to the local machine (e.g., packets going through the fifirewall) reach this hook.

​ 所有不是发往本机的包,即本机充当路由转发功能时(linux主机实现为路由器或防火墙等),会调用本hook

  • LOCAL OUTPUT

    This is the fifirst hook in the outgoing packet path. Packets leaving the local machine always hit this hook.

    本机对外部请求的回复包或者对外发起的请求包,就会触发这个hook

  • POSTROUTING

    This hook is implemented after the routing decision. Source Network Address Translation (SNAT) is registered to this hook. All the packets that leave the local machine reach this hook.

​ 在做出路由决定后,调用本hook。源地址转换,基本就在这个hook阶段完成。所有要离开本机的数据包,就会触发本hook。

具体可以看下图:

image-20230723203225034

​ 按照这篇文章的提法,主要有下面几种网络包流向:

Therefore we can model three kind of traffific flflows, depending on the

destination:

■ Traffific going through the fifirewall, in other words, traffific not going to

the local machine. Such traffific follows the path: PREROUTING 、

FORWARD、 POSTROUTING.

仅仅穿越本机的流量包,即,目的地址不是本机,这样的网络包,会依次经历:

PREROUTING 、FORWARD、POSTROUTING

■ Incoming traffific to the fifirewall, for example, traffific for the local

machine. Such traffific follows the path: PREROUTING INPUT.

发给本机的流量包,路径为:

PREROUTING 、LOCAL INPUT

■ Outgoing traffific from the fifirewall: OUTPUT POSTROUTING.

本机生成的,要出去的流量包(别管是回复别人的那种还是自己发起的,对机器来说都一样,都是要出去的),经历:

OUTPUT 、POSTROUTING

几个时间点说清楚了,那么,这些时间点,回调我们的时候,是查询我们设置的防火墙规则对吧,那么,规则大概长啥样呢?

iptables -I INPUT  -p tcp --dport 8080 -j ACCEPT

比如,上面这就是一个规则,其中,-p tcp --dport 8080就是指定要筛选出哪些数据包来处理,如目标端口8080的,那么,怎么处理呢,这个-j ACCEPT就表示放行。

另外,我们也不可能就一个规则吧,这个规则处理8080的,那我还有其他处理8081端口的规则,所以,最终是一堆规则,一个规则列表。

此时,我们就可以往每个hook点,注册上一个规则集合,即一个规则链,按链中顺序,依次处理。

那么,iptables是这样搞的吗,我们来看看。

iptables中的规则组织形式

此时,可以看下图:

image-20230723204335084

在每个hook点,如左下角的PREROUTING,按理说只需要有一个规则集合就够了,为啥有三个黄色方块(它们唯一指向了一堆PREROUTING阶段的规则集合),也就是说,怎么有三个规则集合呢?

其实,就是因为不同规则大相径庭:

  • 有的规则最终是进行NAT转换,只改改ip、端口这些;
  • 有的规则是进行大改,甚至修改报文,如ip报文中的Type of Service字段
  • 有的规则呢,根本不去动报文,完全不改,比如我们可能就是想打个日志记录下报文
  • 还有的规则,是检查报文,检查完成后,比如防火墙,发现指定端口是不开放的,那么可以直接丢弃报文或者拒绝报文(分别造成客户端读超时、连接reset等异常)
  • 其实还有很多种目标动作

然后,官方就大体根据这些规则,进行了分类,把一个大集合,分成了好几个集合,比如nat集合负责nat相关规则、mangle集合负责改报文字段的规则,如Type of Service、raw集合呢,目前我接触到的有trace、log等规则、像filter呢,就负责对报文检查后进行筛选过滤。

另外呢,像一个报文的生命周期,可能会依次经过:

PREROUTING 、LOCAL  INPUT

那么,在这两个阶段,我们都可以执行规则,比如,filter集合里的规则,在这两个hook点都可以执行,所以,filter表中,包含了多个hook点的规则集合;像nat集合里的规则呢,一般就在PREROUTING 、POSTROUTING这两个阶段发挥作用,所以呢,nat表,包含了PREROUTING 、POSTROUTING两个hook点的规则集合,两者互不影响,井水不犯河水。

我个人喜欢上面那张图,下面这张也可以参考:

image-20230723210256615

网上还有一张图,我觉得也很棒(https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg):

image-20230723210446254

下图是只针对转发这种场景,也不错,图都是来源网络,侵删:

image-20230723214351472

如何使用iptables对规则集合进行增删改查

比如,上图中,我想操作左下角的prerouting阶段的raw表:

// -t 指定表名,如raw,-I 表示插入,chain表示在哪个链插入,如PREROUTING,rulenum呢,是在PREROUTING链中插入到第几个,后面的rule-spe就是规则定义:筛选包+对包的操作
iptables [-t table] -I chain [rulenum] rule-specification

比如,我想trace一下发往8080端口的包:

iptables -t raw -I PREROUTING -p tcp -m tcp --dport 8080 -j TRACE

其他操作:

// -R,替换,即修改
iptables [-t table] -R chain rulenum rule-specification
// -D 删除
iptables [-t table] -D chain rulenum
// -L 查询,一般组合使用iptables -nvL,默认查看filter表
iptables [-t table] -L, --list [chain]

其他命令参考man iptablesman iptables-extensions(包含了各种目标操作的讲解)

nat实验

简介

image-20230723212111654

看我上面的图,server1没有实际监听8080端口,server2有监听,假设我客户端只能直接访问server1,那么,我想做的是,在server1上靠iptables的dnat,修改目的ip为server2,达成我访问server2的8080服务的目的。

server1开启转发能力

// 没有持久化,临时修改
echo 1 >/proc/sys/net/ipv4/ip_forward
// 查看
[root@hx168-access ~]# sysctl -p
net.ipv4.ip_forward = 1

因为server1没有监听8080端口,那肯定不能自己处理,所以必须转发给server2,所以需要开启这个功能

增加trace规则,方便调试

iptables -t raw -I PREROUTING -p tcp -m tcp --dport 8080 -j TRACE
iptables -t raw -I PREROUTING -p tcp -m tcp --sport 8080 -j TRACE

目标端口为8080的,表示客户端发出来的;源端口为8080的,表示server2回复的。都加上trace

有问题就去看/var/log/messages日志

在PREROUTING增加DNAT规则

iptables -t nat -I PREROUTING 1 -p tcp -m tcp   --dport 8080 -j DNAT --to-destination  10.80.121.115

即,在网络包刚进来时,因为目标ip是server1,此时如果不进行目标ip修改,就会交给本机处理,所以,我们不能让这事发生,得改成server2.

在filter表的forward链,增加放行规则

iptables -t filter -I FORWARD 1 -p tcp -m tcp --dport 8080 -j ACCEPT
iptables -t filter -I FORWARD 1 -p tcp -m tcp --sport 8080 -j ACCEPT
正向的和反向的,各加一个,免得一会还要再加

在nat表的POSTROUTING链,增加SNAT规则

iptables -t nat -I PREROUTING 1 -p tcp -m tcp --dport 8080 -j SNAT --to-source  10.80.121.114

因为此时发往server2的报文里,源ip还是客户端的ip,如果就这么发过去,server2就会返回报文给客户端,而不是server1,所以得改源ip为server1.

测试

image-20230723213446750

可以看到,完全没问题。

网络报文

在执行上述命令测试时,我在server1上抓包了:

tcpdump -i any tcp port 8080 -w 114.pcap

然后分析114.pcap时,发现就是如下这样,一个简单的三次握手也不简单:

image-20230723213700210

疑问

我一开始有疑问,当server2给server1返回时,目标ip为server1,我们也没有配置什么NAT规则,把目标ip改成客户端的ip,那么,服务器为啥不是把报文交给server1的进程处理,而是原路forward转发呢

这个其实还是因为NAT依赖了netfilter的会话跟踪功能,简单来说,netfilter是有状态的,以tcp举例,tcp连接的建立是因为客户端ip:客户端端口和服务端ip:服务端端口,这个四元组是有来有回的,就是我给你发了消息,你也回我了,此时,netfilter就认为这是一个会话。

所以,在server2给server1返回时,server1拿着server2和server1之间的四元组去查,查到有会话,因此,就按照之前的路径,原路回来。

另外,nat这个table里的链,只在检测到之前不存在会话时,才会进,后续就不会再进了;也就是只有首次报文的时候进nat的链

这个可以参考:

https://serverfault.com/questions/741104/iptables-redirect-works-only-for-first-packet/741108#741108

像上面这个案例,只要执行如下命令,关闭会话跟踪,就执行不成功了:

iptables -t raw -I PREROUTING -p tcp -m tcp -dport 8080 -j NOTRACK

查看会话的命令、工具

[root@hx168-access ~]# cat /proc/net/nf_conntrack
ipv4     2 tcp      6 118 TIME_WAIT src=10.0.240.103 dst=10.80.121.114 sport=8922 dport=8080 src=10.80.121.115 dst=10.80.121.114 sport=8080 dport=8922 [ASSURED] mark=0 zone=0 use=2
yum install conntrack-tools

[root@hx168-access ~]# conntrack -L
tcp      6 118 TIME_WAIT src=10.0.240.103 dst=10.80.121.114 sport=9072 dport=8080 src=10.80.121.115 dst=10.80.121.114 sport=8080 dport=9072 [ASSURED] mark=0 use=1

参考文章

https://www.jianshu.com/p/0fe6aeec8d79,图不错

https://www.linux.org/docs/man8/iptables-extensions.html

https://gist.github.com/tomasinouk/eec152019311b09905cd 关于nat

https://www.netfilter.org/documentation/

https://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html#ss3.1

https://www.usenix.org/system/files/login/articles/892-neira.pdf

标签:iptables,简要,8080,tcp,hook,PREROUTING,NAT,规则
From: https://www.cnblogs.com/grey-wolf/p/17575996.html

相关文章

  • iptables防火墙调试,想打印个日志就这么难
    背景怎么会讲这个话题,这个说来真的长了。但是,长话短说,也是可以的。我前面的文章提到,线上的服务用了c3p0数据库连接池,会偶发连接泄露问题,而分析到最后,又怀疑是db侧主动关闭连接,或者是服务所在机器和db之间有防火墙,防火墙主动关闭了连接。导致我们这边socket看着还健康,实际在对端......
  • 虚拟化(4) qemu用NAT上网
    通过前面3篇的探索,NAT方式应该可以实现了,不会的网友可以滴滴我。以上涉及的命令+图形库就可以自己实现一个类似vmware或vbox的虚机软件了。我感觉qemu源码真的很重要,如果读明白,那么自己也可以在其他系统如window和mac实现虚拟化,下载qemu源码开始阅读.........
  • 网络抓包,https加密解析简要过程
    HTTPS(HypertextTransferProtocolSecure)是一种在传输过程中使用SSL/TLS加密的HTTP协议,用于保护Web通信的安全性和隐私。HTTPS在常规HTTP的基础上添加了加密层,使数据在传输过程中得以加密,从而提供更高的安全性和保护用户数据不被窃取或篡改。以下是HTTPS加密解析的简要过程:客户端......
  • NativePHP Beta 已发布
    参考https://learnku.com/articles/82569https://nativephp.com/正文php做客户端......
  • hibernate反向工程生成的实体类就不能正确放在指定的包路径下
    hibernate反向工程生成的实体类就不能正确放在指定的包路径下  描述:使用hibernate反向工程生成实体类时,类文件可以正确生成在src的一级目录下但在二级或多级目录时就会生成在src的默认包下.例如:表User,它有俩个字段username和password.在src下的一级目录为hibernate,存放User......
  • Hibernate初始化时在OneToOneSecondPass类中出现NullPointerException
    启动项目 Hibernate随即报错Causedby:java.lang.NullPointerException   atorg.hibernate.cfg.OneToOneSecondPass.doSecondPass(OneToOneSecondPass.java:135)  原因: 主类方,无外键方@OneToOne(mappedBy="carveEReviewproject",targetEntity=CarveEReviewcomment.cla......
  • 通过iptables做本地端口分流实现高性能服务
    根据以往经验,在高配置服务器上部署Java服务,建议部署多个JVM实例,以提升JVM示例内存回收效率;此时面临负载分发问题,常规想法是通过Nginx或者Apache做负载分流。然而在高并发情况下无论外置负载还是本机负载,都需要处理TCP端口占用问题,处理起来并不简单。近期在做一个高性能测试时候,......
  • element-ui pagination分页组件 点击一次页面跳转触发两次current-change请求
    在项目中使用element编写前端页面时,发现在使用pagination分页组件的时候,出现一个坑。情况是每一次点击页面切换,都会重复触发两次页面切换current-change事件。无论是点击后面的页码或者是下一页或者是跳转到某个页面都会触发两次。第一次正常触发,第二次触发后会返回首页。经过多......
  • react-native 调用手机自带分享
    实现效果 importSharefrom'react-native-share'importViewShotfrom'react-native-view-shot'constshotRef=useRef<ViewShot>(null)constgetTime=()=>{returnnewDate().getTime().toString()}constOnShare=()=&g......
  • .NET Native AOT的静态库与动态库
    .NET不仅可以使用C静态库与动态库,也可以将.NET实现的函数导出为C静态库与动态库。在没有NativeAot之前,.NET只能通过P/Invoke享受C/C++生态,而在NativeAot之后,不仅可以享受这些生态,还可以开发SDK供其他语言调用。.NETNativeAOT的NativeLib参数用于指定本机库的类型。在.NET7......