NAT实验一

环境

Linux:centos 7.9

br_bond0:192.168.79.77、192.168.79.78

bond1:trunk

需求

访问192.168.207.112会nat到192.168.79.77

方案

在host创建一个namespace NAT_207_TO_79

创建veth pair,一端桥接到br_bond0,一端放入namespace

创建bond1 vlan 207子网卡,并放入到namespace中

配置iptables转发策略

bond1.vlan_207: 192.168.207.112/24

veth0_1: 192.168.79.20/24

默认网关:192.168.207.254

实践

  • 创建namespace
# ip netns add namespace NAT_207_TO_79
  • 创建veth pair
# ip link add veth0_0 type veth peer name veth0_1
  • 创建bond1 vlan 207子网卡
# ip link add link bond1 name bond1.vlan_207 type vlan id 207
  • 将veth0_0桥接到br_bond0
# brctl addif br_bond0 veth0_0
  • 将veth0_1添加到NAT_207_TO_79 namespace中
# ip link set veth0_1 netns NAT_207_TO_79
  • 将bond1.vlan_207添加到NAT_207_TO_79 namespace中
# ip link set bond1.vlan_207 netns NAT_207_TO_79
  • 将veth0_0、veth0_1、bond1.vlan_207 网卡up
# ip link set dev veth0_0 up
# ip netns exec NAT_207_TO_79 bash -c "ip link set dev veth0_1 up"
# ip netns exec NAT_207_TO_79 bash -c "ip link set dev bond1.vlan_207 up"
  • 配置bond1.vlan_207、veth0_1 IP地址
# ip netns exec NAT_207_TO_79 bash -c "ip addr add 192.168.207.112/24 dev bond1.vlan_207"
# ip netns exec NAT_207_TO_79 bash -c "ip addr add 192.168.79.20/24 dev veth0_1"
  • 配置namespace默认路由
# ip netns exec NAT_207_TO_79 bash -c "ip route add 0.0.0.0/0 via 192.168.207.254"
  • 创建iptables nat规则
# ip netns exec NAT_207_TO_79 bash -c "iptables -t nat -A PREROUTING -d 192.168.207.112/32  -j DNAT --to-destination 192.168.79.77"
# ip netns exec NAT_207_TO_79 bash -c "iptables -t nat -A POSTROUTING -s 192.168.79.77 -j SNAT --to-source 192.168.207.112"
  • 开启端口转发
# _state=$(cat /proc/sys/net/ipv4/ip_forward);if [ "$_state" -ne "1" ];then echo 1 > /proc/sys/net/ipv4/ip_forward;fi && unset _state

问题

namespace ping网关报错Destination Host Prohibited
  • 原因:主机上安装了docker,对FORWARD链做了策略
  • 解决方法:在host上添加允许策略
# iptables -I FORWARD -s 192.168.79.20/32 -j ACCEPT
# iptables -I FORWARD -d 192.168.79.20/32 -j ACCEPT
配置NAT后不生效
  • 原因:抓包发现192.168.79.77在回包给client端时走的自己的路由,如果192.168.79.77到client端下一跳地址不是192.168.79.20会导致无法SNAT,client收到不明来源的包会丢弃
  • 解决方法一:在host上添加到client端路由下一跳为192.168.79.20,例如client IP为192.168.135.39/24
# ip route add 192.168.135.0/24 via 192.168.79.20
  • 解决方法二:修改配置方案iptables nat规则修改如下(192.168.79.77直接二层到namespace中)(其实方案也应该是这种才对)
# ip netns exec NAT_207_TO_79 bash -c "iptables -t nat -A PREROUTING -d 192.168.207.112/32  -j DNAT --to-destination 192.168.79.77"
# ip netns exec NAT_207_TO_79 bash -c "iptables -t nat -I POSTROUTING -d 192.168.79.77 -j SNAT --to-source 192.168.79.20"

脚本配置

由于时间原因,未调研(网上方法是通过rc.local实现)能否永久配置,可通过如下脚本配置

  • 配置脚本
# cat >> nat_207_to_79.sh << EOF
#!/bin/bash
echo '[------create namespace NAT_207_TO_79------]'
ip netns add NAT_207_TO_79
ip netns ls | grep NAT_207_TO_79
echo '[------create bond1.vlan_207------]'
ip link add link bond1 name bond1.vlan_207 type vlan id 207
ip link show dev bond1.vlan_207
echo '[------create veth pair(veth0_0,veth0_1)------]'
ip link add veth0_0 type veth peer name veth0_1
ip link show dev veth0_0
ip link show dev veth0_1
echo '[------add bond1.vlan_207 to NAT_207_TO_79------]'
ip link set bond1.vlan_207 netns NAT_207_TO_79
ip netns exec NAT_207_TO_79 bash -c "ip link show dev bond1.vlan_207"
echo '[------add veth0_0 to br_bond0------]'
brctl addif br_bond0 veth0_0
brctl show br_bond0 | grep -E "interface|br_bond0|veth0_0"
echo '[------add veth0_1 to NAT_207_TO_79------]'
ip link set veth0_1 netns NAT_207_TO_79
ip netns exec NAT_207_TO_79 bash -c "ip link show dev veth0_1"
echo '[------up bond1.vlan_207,veth0_0,veth0_1------]'
ip link set dev veth0_0 up
ip netns exec NAT_207_TO_79 bash -c "ip link set dev bond1.vlan_207 up"
ip netns exec NAT_207_TO_79 bash -c "ip link set dev veth0_1 up"
ip netns exec NAT_207_TO_79 bash -c "ip link show dev bond1.vlan_207 | grep bond1.vlan_207"
ip link show dev veth0_0 | grep veth0_0
ip netns exec NAT_207_TO_79 bash -c "ip link show dev veth0_1 | grep veth0_1"
echo '[------config ip addr 192.168.207.112/24 to bond1.vlan_207------]'
ip netns exec NAT_207_TO_79 bash -c "ip addr add 192.168.207.112/24 dev bond1.vlan_207"
ip netns exec NAT_207_TO_79 bash -c "ip -4 addr show  dev bond1.vlan_207 | grep inet"
echo '[------config ip addr 192.168.79.20/24 to veth0_1------]'
ip netns exec NAT_207_TO_79 bash -c "ip addr add 192.168.79.20/24 dev veth0_1"
ip netns exec NAT_207_TO_79 bash -c "ip -4 addr show veth0_1 | grep inet"
echo '[------config default gw 192.168.207.254 to NAT_207_TO_79------]'
ip netns exec NAT_207_TO_79 bash -c "ip route add 0.0.0.0/0 via 192.168.207.254"
ip netns exec NAT_207_TO_79 bash -c "ip route show | grep -E '192.168.207.254|0.0.0.0|default'"
echo '[------config ip_forward------]'
ip netns exec NAT_207_TO_79 bash -c '_state=$(cat /proc/sys/net/ipv4/ip_forward);if [ "$_state" -ne "1" ];then echo 1 > /proc/sys/net/ipv4/ip_forward;fi && unset _state'
ip netns exec NAT_207_TO_79 bash -c "cat /proc/sys/net/ipv4/ip_forward"
echo '[------config ipatbles nat rule------]'
ip netns exec NAT_207_TO_79 bash -c "iptables -t nat -A PREROUTING -d 192.168.207.112/32  -j DNAT --to-destination 192.168.79.77"
ip netns exec NAT_207_TO_79 bash -c "iptables -t nat -I POSTROUTING -d 192.168.79.77 -j SNAT --to-source 192.168.79.20"
ip netns exec NAT_207_TO_79 bash -c "iptables -t nat -nvL --line-numbers | grep -E 'SNAT|DNAT' | grep -E '192.168.207.112|192.168.79.77'"
echo '[------config host iptables FORWARD rule(allow 192.168.79.20/32)------]'
total_allow_nums=$(iptables -nvL FORWARD | grep 192.168.79.20 | grep ACCEPT | wc -l)
if [ "$total_allow_nums" -ne "2" ];then
    iptables -I FORWARD -s 192.168.79.20/32 -j ACCEPT;
    iptables -I FORWARD -d 192.168.79.20/32 -j ACCEPT;
fi
iptables -nvL FORWARD | grep 192.168.79.20 | grep ACCEPT
EOF
  • 删除配置
# cat >> clean_nat_207_to_79.sh << EOF
#!/bin/bash
echo '[------del namespace NAT_207_TO_79------]'
ip netns delete NAT_207_TO_79
echo '[------del bond1.vlan_207,veth pair(veth0_0,veth0_1)------]'
ip link del dev veth0_0
echo '[------del host iptables FORWARD rule(del allow 192.168.79.20/32)------]'
total_allow_nums=$(iptables -nvL FORWARD | grep 192.168.79.20 | grep ACCEPT | wc -l)
if [ "$total_allow_nums" -ne "0" ];then
    iptables -D FORWARD -s 192.168.79.20/32 -j ACCEPT;
    iptables -D FORWARD -d 192.168.79.20/32 -j ACCEPT;
fi
EOF

排查思路

  • 通过tcpdump抓包查看src和dst
  • 通过conntrack -L查看链接跟踪
  • 根据iptables流程图分析(搬运网上大佬的图)

使用iptables实现NAT_NAT


使用iptables实现NAT_抓包_02

使用iptables实现NAT_NAT_03

NAT实验二

环境

Linux:centos 7.9

br_bond0:172.28.17.77 255.255.248.0

br_bond1:192.168.79.77 255.255.255.0

需求

将这个主机配置成nat网关,192.168.79.0/24的地址通过SNAT成172.28.17.77出去访问外网

方案

使用iptables实现

  • 配置数据包转发
# echo 1 > /proc/sys/net/ipv4/ip_forward (临时生效)
# echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf  (永久生效,重启或者执行sysctl -p)
  • 配置iptables nat规则
# iptables -t nat -I POSTROUTING -s 192.168.79.0/24 -j SNAT --to-source 172.28.17.77
# iptables -t nat -I POSTROUTING -s 192.168.79.77/32 -j RETURN  (防止本机也被SANT成172.28.17.77,注意顺序)
  • 配置filter规则允许进出(重要)
# iptables -t filter -I FORWARD -s 192.168.79.0/24 -j ACCEPT
# iptables -t filter -I FORWARD -d 192.168.79.0/24 -j ACCEPT

排查思路

根据iptables流程图和抓包分析