Skip to the content.

Iptables

31 May 2023 - joy717

iptables

image

两张表

iptables --> 网络层(上图的绿色的Network level)

ebtables --> 数据链路层(上图的蓝色的Bridge level)

ebtablesiptables作用类似,只不过是基于数据链路层的处理,处于iptables的外层。入方向,先经过ebtables再进入iptables,出方向,则先经过iptables,再进入ebtables

iptable 包在各个4表5链上的执行顺序

https://www.linuxtopia.org/Linux_Firewall_iptables/c951.html

不知道这个文档描述是否与比较新的内核一致。

iptables set-xmark 解释

https://stackoverflow.com/questions/22003409/some-questions-about-set-xmark-in-iptables https://blog.csdn.net/qq_31977125/article/details/124208384

命令格式:--set-xmark value/mask

实际计算公式为:ctmark = (ctmark AND NOT mask) XOR value (ctmark为数据包在--set-mark之前的数据包mark值,即原始值) 即,Zero out the bits given by mask and XOR value into the ctmark将mask给的位抹零,再将 原始值 XOR value

iptables -j(jump) -g(goto)区别

https://serverfault.com/questions/675559/iptables-using-goto-jump-what-is-the-return-behaviour

https://stackoverflow.com/questions/31606411/iptables-j-vs-g-parameters

-j 返回到调用-j的下一条记录继续执行

-g 不是返回到调用-g的下一条记录继续执行,而是返回到最近的调用-j的下一条记录继续执行

# 例子

-A CHAIN-A -j CHAIN-SUB
-A CHAIN-A -m comment 'chain-a'
-A CHAIN-SUB -m comment 'hello'

# -j 由`CHAIN-A`到 `CHAIN-SUB`, 当`CHAIN-SUB`执行到底或者RETURN后,回到调用jump的位置执行下一条规则,即:`-A CHAIN-A -m comment 'chain-a'`

-A CHAIN-PART -j CHAIN-XXX
-A CHAIN-PART -j CHAIN-A
-A CHAIN-PART -m comment 'chain-part'

-A CHAIN-A -g CHAIN-SUB
-A CHAIN-A -m comment 'chain-a'
-A CHAIN-SUB -m comment 'hello'

# -g 由`CHAIN-PART`jump到`CHAIN-A`,再goto到`CHAIN-SUB`,当`CHAIN-SUB`执行到底或者RETURN后,不是回到调用goto的位置执行下一条(`-A CHAIN-A -m comment 'chain-a'`),
# 而是返回最近的一个调用jump的位置,继续往下执行,即`-A CHAIN-PART -m comment 'chain-part'`

各种JUMP的执行顺序

https://www.jianshu.com/p/15bd803e3bb8

https://www.flftuu.com/2021/07/12/iptables%E7%94%A8%E6%B3%95/

kube-proxy iptable/ipvs 详解

https://zhuanlan.zhihu.com/p/94418251

https://www.digihunch.com/2020/11/ipvs-iptables-and-kube-proxy/

iptables链路表

iptables_workflow

iptables 扩展组件

https://ipset.netfilter.org/iptables-extensions.man.html

iptables查看某个module的帮助

iptables -m addrtype --help

路由表与netfilter交互

image

Linux路由表其实有2个主要概念:

Linux可以配置很多很多策略,数据包将依次通过各个策略,一旦匹配某个策略则进一步应用策略对应的路由表,如果当前路由表无法匹配到路由则继续执行后续策略匹配。

MASQ的选择src ip的逻辑

Masq会导致多执行一次路由选择,确定出口网卡上与目标地址的路由结果匹配的ip地址。

如果不匹配,查找出口网卡的master设备。

如果不匹配,则遍历所有设备,只关心master设备

路由之后再修改src IP

https://elixir.bootlin.com/linux/latest/source/net/netfilter/nf_nat_masquerade.c#L44

https://cloud.tencent.com/developer/article/2144773

允许iptables的trace

# 添加TRACE的规则
iptables -t raw -I PREROUTING -s 172.31.1.136 -m comment --comment "prerouting start" -j TRACE -w 10

# 正常在/var/log/message 里面会输出`kernel: TRACE:`字眼的日志,如果没有,可以执行下面命令,开启日志
# 添加规则的时候,有可能报没有target的错误,需要加载一下nf_log_ipv4的模块
modprobe nf_log_ipv4
sysctl net.netfilter.nf_log.2=nf_log_ipv4

# 如果发现有些包没有被log记录下来,可能是log系统的限流导致,比如
# `imjournal: begin to drop messages due to rate-limiting`
# 修改/etc/rsyslog.conf, 设置:(需包含最前面的$)
$imjournalRatelimitInterval 0
$imjournalRatelimitBurst 0

# 重启rsyslog服务
systemctl restart rsyslog

ipvs

经典架构

        ____________
       |            |192.168.1.254 (eth1)
       |  client    |----------------------
       |____________|                     |
     CIP=192.168.2.254 (eth0)             |
              |                           |
              |                           |
     VIP=192.168.2.110 (eth0)             |
        ____________                      |
       |            |                     |
       |  director  |                     |
       |____________|                     |
     DIP=192.168.1.9 (eth1, arps)         |
              |                           |
           (switch)------------------------
              |
     RIP=192.168.1.2 (eth0)
     VIP=192.168.2.110 (for LVS-DR, lo:0, no_arp)
        _____________
       |             |
       | realserver  |
       |_____________|

词汇

| IP | 描述 | |-----|-----------------------------------------------------------------------------------| | CIP | Client IP | | VIP | Virtual IP (即LB的ip) | | DIP | Director IP (更普遍的情况是,lvs是一个网关,隔离了外部网络-Client 跟内部网络)-RealServerDIP为内部网络这一侧的IP | | RIP | RealServer IP (实际服务的IP) |

ipvs原理实现

https://github.com/liexusong/linux-source-code-analyze/blob/master/lvs-principle-and-source-analysis-part2.md

官方文档:http://www.linuxvirtualserver.org/Documents.html

ipvs与netfilter交互

http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.filter_rules.html

交互

ipvs与iptables优先级

Modules register with a priority, the lowest priority getting to look at the packets first. LVS registers itself with a higher priority than iptables rules, and thus iptables will get the packet first and then LVS

所以,ipvs转发时:PREROUTING->路由表->INPUT(iptables)->INPUT(lvs)->POSTROUTING

ipvsadm显示的masq

ipvs的转发模式包含:

使用ipvs以及相关的配置

https://medium.com/google-cloud/load-balancing-with-ipvs-1c0a48476c4d

http://www.linuxvirtualserver.org/VS-NAT.html

ipvs-nat限制条件

client->lvs->realServer

ipvs只在lvs这边设置dnat,并没有针对src ip做修改,因此realServer收到的包src ip为client的ip,dst ip为realServer的ip。

当realServer发响应包回去的时候,目的地址为client的ip,就无法回到lvs这边来。

ip地址变化情况:

| 包当前所在位置 | src ip | dst ip | |------------|--------|--------| | client | CIP | VIP | | lvs | CIP | RIP | | RealServer | CIP | RIP |

一种最直接的方式,就是将realServer的默认网关配置为lvs (DIP,Director IP)。

另外一种方式是,在realServer这边配置路由,将来自realServer服务ip的包,转到lvs这边,比如:

realserver# echo 80 lvs >> /etc/iproute2/rt_tables
realserver# ip route add default <address on director, eg DIP> table lvs
realserver# ip rule add from <RIP> table lvs

iptables例子解释

addrtype 为LOCAL

-A KUBE-SERVICES -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS

如果目标地址是LOCAL的,则jump到KUBE-NODEPORTS。 什么是LOCAL?本地所有网卡上的IP地址,都属于LOCAL。换言之,如果是发往本机器(ip与网卡上任一匹配),则jump

ip route show table local type local

可显示所有的本地ip

calico规则

-A cali-POSTROUTING -o vxlan.calico -m comment --comment "cali:e9dnSgSVNmIcpVhP" -m addrtype ! --src-type LOCAL --limit-iface-out -m addrtype --src-type LOCAL -j MASQUERADE

ADDRTYPE match src-type LOCAL:LOCAL 表示主机上分配的任何 IP 地址,包括 127.0.0.1 和 其他 IP,规则含义是源地址是本地 IP

ADDRTYPE match src-type !LOCAL limit-out: limit-iface-out 限制了 LOCAL 表示的 IP 内容,此时的 LOCAL 只包括 Package 发出设备上的 IP,即 src-type !LOCAL limit-out 的含义是源地址 IP 是 除 Package 发出设备以外的本地 IP

综上 cali-POSTROUTING 进行 MASQUERADE 的条件是:src 是本地地址,并且 src 地址 ip 不能是 out-interface 的 ip。

iptables 空链表

*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [37616:23606638]
:cali-PREROUTING - [0:0]
-A PREROUTING -m comment --comment "cali:6gwbT8clXdHdC1b1" -j cali-PREROUTING

这边可以看到,-A PREROUTING -m comment --comment "cali:6gwbT8clXdHdC1b1" -j cali-PREROUTING,jump到cali-PREROUTING,但cali-PREROUTING实际为空链表。 估计是拿来预定义占坑用的。

bridge 配置

-m physdev 此module配置,是给bridge使用的。

iptables与bridge配合使用,可参考:

https://opengers.github.io/openstack/openstack-base-virtual-network-devices-bridge-and-vlan/ 与bridge

k8s ipvs使用

https://zhuanlan.zhihu.com/p/110860643

https://kubernetes.io/blog/2018/07/09/ipvs-based-in-cluster-load-balancing-deep-dive/

k8s nodeport svc + hostNetwork

NodePort类型的svc,如果后端的pod使用的是hostNetwork,则svc的nodeport无法正常访问。

https://stackoverflow.com/questions/42480525/kubenetes-pod-hostnetwork-cause-nodeport-does-not-work