iptable masquerade中源地址选择问题

背景

在iptable/ip6table上可以在nat table上完成SNAT和DNAT操作。SNAT指将匹配ip包的源地址进行修改,DNAT指将匹配ip包的目的地址进行修改。

  • SNAT 当在内网主机需要访问公网(internet)时刻,在防火墙上就会进行SNAT操作,出防火墙时刻ip报文的源地址被转换为防火墙的地址。
  • DNAT 同样如果公网要访问内网的主机,它只能访问到防火墙,防火墙完成DNAT转换,将IP报文目标地址转换为防火墙在内网的地址再将ip包转发到小网上。

在iptables命令上,SNAT书写规则需要写下SNAT转换的目标地址,这里必须明确写出自己需要转换成的地址
iptables -t nat -A POSTROUTING -s 10.8.0.0/255.255.255.0 -o eth0 -j snat –to-source 192.168.5.3-192.168.5.5
但是在某些场合,iptable规则编写的时候源ip地址并不固定或可获取。那么此时Linux引入了masquerade动作,这个规则的意思就是Ip包从哪个interface出去,那么src ip就转换为此interface的ip地址。

那么当一个interface上有多个ip地址的时候怎么办呢?例如下面的接口eth0有两个相同网段的ip地址,那么masquerade会选择哪一个ip作为源ip地址呢?例如下面的情况

$iptables -t nat -A POSTROUTING -o eth0 -j masquerade
$ip addr show dev eth0
eth0:<BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
  link/ether 00:e0:4c:9c:13:b7 brd ff:ff:ff:ff:ff:ff
  inet 192.168.120.156/23 brd 192.168.120.255 scope global eth0
  inet 192.168.120.157/23 brd 192.168.120.255 scope global eth0

多ip时刻masquerade 源ip选择规则

总体上来讲,masquerade在选择源ip地址时刻的选择规则其实和路由选择的源地址选择是一致的。最简单的获取masquerade源地址的方法是通过下面命令:
ip route get <dstip>
这在Linux源码上看得更清楚,下面是ipv4场景下masquerade选源路由的方法

unsigned int
nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
               const struct nf_nat_range2 *range,
               const struct net_device *out)
{
    ......
    newsrc = inet_select_addr(out, nh, RT_SCOPE_UNIVERSE);
    if (!newsrc) {
        pr_info("%s ate my IP address\n", out->name);
        return NF_DROP;
    }

    nat = nf_ct_nat_ext_add(ct);
    if (nat)
        nat->masq_index = out->ifindex;

    /* Transfer from original range. */
    memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
    memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
    newrange.flags       = range->flags | NF_NAT_RANGE_MAP_IPS;
    newrange.min_addr.ip = newsrc;
    newrange.max_addr.ip = newsrc;
    newrange.min_proto   = range->min_proto;
    newrange.max_proto   = range->max_proto;

    /* Hand modified range to generic setup. */
    return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
}

上表中inet_select_addr(out,nh,RT_SCOPE_UNIVERSE)就是根据out,路由,选择源ip地址的过程。

ipv6场景下masquerade源ip地址的选择

在ipv4场景上,masquerade 源地址选择和路由源地址选择是也就是一致的,但是在ipv6场合就有一定的区别了。
ipv6场景下masquerade动作的执行函数为:

nf_nat_masquerade_ipv6(struct sk_buff *skb,const struct nf_nat_range* range,
                                      const struct net_device *out)
{
     ......
     if( ipv6_dev_get_saddr(dev_net(out),out, &ipv6_hdr(skb)->daddr,0,&src) < 0)
         return NF_DROP;
    ......
}

可见它的核心函数为ipv6_dev_get_saddr(),此函数执行的就是ipv6地址协议规定的源地址选择逻辑。而ipv6路由选择源地址函数实现为:

int ip6_route_get_saddr(struct net*net,struct rt6_info *rt,const struct in6_addr *daddr,
                                      unsigned int prefs,struct in6_addr *saddr)
{
......
   if(rt->rt6i_presrc.plen)
       *saddr=rt->rt6i_prefsrc.addr;
   else
      err=ipv6_dev_get_saddr(net,dev?idev->dev:NULL,daddr,prefs,saddr);
   return err;
}

可以看到在ipv6 路由选择源地址中,并不是第一选择ipv6_dev_get_saddr()函数的。而是先选择ipv6 route 表中选路结果是否设置了prefsrc。上述函数中入参rt表示的是ipv6 route 路由表选择的entry。ipv6路由选择具体由ip6_route_output()—>fib6_fule_lookup查询而来。
是否设置了ipv6路由的prefer src可以通过ip -6 route list 命令查看到,例如:

$ip -6 route list
......
2001::/64 dev eth0 src 2001::dbc:71 metric 15
......

可以看到针对2001::/64网段的dest ip,选路是eth0,prefer src为 2001::dbc:71
设置路由entry的prefer src命令为:ip -6 route add 2001::/64 dev eth0 scope link src 2001::dbc:71 metric 15

ipv6协议规定的源地址选择

ipv6协议中规定了严格源地址/目标地址选择机制,主要涉及到RFC 3484.也就是说当ipv6源地址尚未确定时刻,按照RFC3484规定的8条规则选择一个源ip地址。这8条规则(rules)是有优先级的,从优先级从高到低排列如下:

  • rule1优先选择与目标地址相同的地址
  • rule2优先scope与目标scope比较接近的,且scope更大的地址
  • rule3优先preferred地址
  • rule4优选home地址
  • rule5优先和路由出口在同一网卡上的地址。
  • rule6优选Label匹配地址
  • rule7优选根据系统配置非临时/临时地址
  • rule8优选和目标地址最长前缀匹配的地址
rule2

所谓ipv6地址的scope(作用域)分为下面几类:

  • fe80::/10 链路本地地址,只出现在二层链路上,不能通过三层设备
  • fc00::/7 ULA地址,不能出现在internet上,只能在组织内部。
  • 2002::16 ipv6 to ipv4地址
  • 全球唯一地址
    scope也就是ipv6 地址分类。scope选择约接近的,那么源和目的的物理距离理论上应该更近。scope选择更大的保障了此地址可达性更高。

rule6

ipv6在选择地址时刻,还会进行目的地址和源地址的Label匹配,当匹配到固定的一对label时刻,匹配完成:
1.匹配时刻是按照目标地址最长前缀匹配方式,就是前缀匹配长度最长的label获胜,如此选出一个目标label;
2.按照源地址最长前缀匹配方式,找到一个label,这就是源label;

  1. 如果只有一个源地址的源label=目标label,查找完成。
  2. 如果多个源地址都出现匹配,那么选取优先级最高的匹配。
    设置ipaddesslabel的方法是通过下面命令:
ip addrlabel add prefix $目标地址网段 label label号
ip addrlabel add prefix $源地址网段 label label号

下面命令可以查看lpv6 address label
ip addrlabel list

总结

单接口上有多个ip地址的时刻,masquerade源地址选择方式如下:

  • ipv4场合,masquerade源地址选择和route选择源地址选择一致。
  • ipv6场合下,masquerade源地址选择和route选择源地址不完全一致。route选择源地址,优先选择route中配置了prefer src的地址,其次才是ipv6源地址选择8条规则按规则优先级从高到低选择;masquerade选择则完全遵从ipv6 源地址选择的8条规则。

参考

blog.csdn.net/dog250/article/details/87815123

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容