前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >learning:NAT-ED twice-nat功能(1)

learning:NAT-ED twice-nat功能(1)

作者头像
dpdk-vpp源码解读
发布2024-06-03 15:30:16
1130
发布2024-06-03 15:30:16
举报
文章被收录于专栏:DPDK VPP源码分析

微信公众号:DPDK VPP源码分析 关注公众号可了解更多的学习资源,请留言:资料。 加入vpp相关的微信群,请留言:加群,扫码加我微信,注明加群。 vpp-dpdk相关学习资料:https://github.com/jin13417/dpdk-vpp-learning。 公众号回复:nat 、ipsec,获取对应学习资料 版权归本公众号所有,如需转载请注明出处。 如果你觉得内容对你有帮助,欢迎转发、点赞、赞赏[1]

近期,我们接到客户的一项明确需求:实现外部网络对内部网络特定服务(例如Web服务器、邮件服务)的无地域限制的随机访问。针对这一需求,NAT技术中的“两次NAT”(Twice NAT) 功能脱颖而出,成为理想的解决方案。此功能专为这类场景定制,能够有效地将源自外部、指向公共IP及端口的访问请求,精准桥接到内部网络中相对应的服务主机上。

两次NAT技术赋予在单一规则下同时转换数据包的源头与目标地址的能力,极大增强了网络配置的灵活性。当前实施重点聚焦于NAT44协议,专门支持由外网向内网服务会话的双向转换。值得注意的是,静态映射配置下的两次NAT仅适用于那些由外部网络发起到本地网络的会话初始化过程,确保了对外服务的同时保持了内网结构的安全与隔离性。

正好,VPP(Vector Packet Processing)平台在其NAT-ED模式下内置了对两次NAT(Twice NAT)功能的支持。VPP官方文档提供了详尽的配置指南,为了实践这一特性,本篇文章将遵循这些官方指导,逐步搭建实验环境,以验证两次NAT功能的实际应用效果。

参考官方文档网络架构,在腾讯云主机上搭建验证环境,网络拓扑如下:

代码语言:javascript
复制
+--------------------------+
|   linux netns inside     |
| 10.0.0.2/24 (local host) |
+--------------------------+
            |
+---------------------------------+
| 10.0.0.1/24 (tap1) (nat inside) |
| 20.0.0.1/24 (tap2) (nat outside)|
|             vpp                 |
+---------------------------------+
            |
+---------------------------+
| 20.0.0.2/24 (remote host) |
|   linux netns outside     |
+---------------------------+

在linux内核上创建2个命令空间 inside和outside,然后在vpp中分别创建两个tap接口,tap1实现vpp和命名空间inside直接通信。tap2实现vpp和命名空间outside通信。vpp使能NAT功能,并配置路由前NAT(理论上路由后NAT也可以,本文完全参照官方文档配置实现),具体配置如下:

  • 内核创建2个命名空间
代码语言:javascript
复制
ip netns add inside
ip netns add outside
  • 创建两个tap接口
代码语言:javascript
复制
creat tap id 1 host-ns inside host-ip4-addr 10.0.0.2/24 host-ip4-gw 10.0.0.1 host-if-name tap1

creat tap id 2 host-ns outside host-ip4-addr 20.0.0.2/24 host-ip4-gw 20.0.0.1 host-if-name tap2


set interface state tap1 up
set interface ip address tap1 10.0.0.1/24
set interface state tap2 up
set interface ip address tap2 20.0.0.1/24

在创建tap接口时,需要指定设置内核tap1接口ip地址及默认网关。

  • NAT基本配置
代码语言:javascript
复制
#启用nat插件
nat44 plugin enable sessions 1000
#配置内部接口
set interface nat44 in tap1
#配置外部接口
set interface nat44 out tap2
#设置nat地址池和twice-nat地址池
nat44 add address 192.168.60.101
nat44 add address 20.0.0.1 twice-nat

此处NAT地址池twice-nat地址池配置和VPP官方文档中设置正好是相反的。将外部访问地址设置到NAT地址池中,将内网接口设置到twice-nat地址池中。

  • 添加两次NAT的映射
代码语言:javascript
复制
nat44 add static mapping tcp local 10.0.0.2 5201 external 192.168.160.101 5201 twice-nat 

这里需要注意,在官方文档中external 地址写的不是twice-nat地址池的地址,这里是存在问题的。上面静态NAT映射配置完之后,我们分别查询当前nat会话为空,flow-hash存在2条记录,如下所示:

代码语言:javascript
复制
#查询静态配置
dpdk-vpp源码分析: show nat44 static mappings 
NAT44 static mappings:
 TCP local 10.0.0.2:5201 external 192.168.160.101:5201 vrf 0 twice-nat 
#查询会话表
dpdk-vpp源码分析: show nat44 sessions 
NAT44 ED sessions:
-------- thread 0 vpp_main: 0 sessions --------
#查询hash tables表
dpdk-vpp源码分析: show nat44 hash tables detail
Hash table 'ed-flow-hash'
[288]: heap offset 44083784, len 1, refcnt 2, linear 0
    0: local 10.0.0.2:5201 remote 0.0.0.0:0 proto TCP fib 0 thread-index 0 session-index 0
[875]: heap offset 44144832, len 1, refcnt 2, linear 0
    0: local 0.0.0.0:0 remote 192.168.160.101:5201 proto TCP fib 0 thread-index 0 session-index 0
    2 active elements 2 active buckets
    0 free lists
    0 linear search buckets
    heap: 1 chunk(s) allocated
          bytes: used 104k, scrap 0

配置完NAT映射表之后生成2个2个flow-hash表,其中875对应的是out2in反向;288对应的in2out方向。这两个表的作用就是用来生成NAT会话的。

接下来在inside命名空间开启IPerf3 服务端,然后在outside命名空间设置iperf3客户端连接服务器。连接正常建立。

NAT会话翻译如下:

从外到内翻译: 源地址:20.0.0.2 -> 192.168.160.101 目标地址:20.0.0.1 -> 10.0.0.2 从内到外的翻译: 源地址:10.0.0.2 -> 20.0.0.1 目标地址:192.168.160.101 -> 20.0.0.2

我们抓取了IPerf3建立tcp连接SYN交互trace流程:

代码语言:javascript
复制
00:04:48:324556: virtio-input
  virtio: hw_if_index 2 next-index 4 vring 0 len 74
    hdr: flags 0x00 gso_type 0x00 hdr_len 0 gso_size 0 csum_start 0 csum_offset 0 num_buffers 1
00:04:48:324561: ethernet-input
  frame: flags 0x1, hw-if-index 2, sw-if-index 2
  IP4: 02:fe:79:00:b8:be -> 02:fe:b9:84:d0:66
00:04:48:324567: ip4-input
  TCP: 20.0.0.2 -> 192.168.160.101
    tos 0x00, ttl 64, length 60, checksum 0xbf15 dscp CS0 ecn NON_ECN
    fragment id 0x0697, flags DONT_FRAGMENT
  TCP: 52558 -> 5201
    seq. 0xd803aaad ack 0x00000000
    flags 0x02 SYN, tcp header: 40 bytes
    window 64240, checksum 0x539c
    options:
      mss 1460, window scale -139065856, timestamp -139065856, echo/reflected timestamp, sack permitted
00:04:48:324571: ip4-sv-reassembly-feature
  [not-fragmented]
00:04:48:324574: nat-pre-out2in
  out2in next_index 6 arc_next_index 10
00:04:48:324576: nat44-ed-out2in
  NAT44_OUT2IN_ED_FAST_PATH: sw_if_index 2, next index 7
  search key local 20.0.0.2:52558 remote 192.168.160.101:5201 proto TCP fib 0 thread-index 0 session-index 0
  slow path because lookup failed
00:04:48:324579: nat44-ed-out2in-slowpath
  NAT44_OUT2IN_ED_SLOW_PATH: sw_if_index 2, next index 10, session 1, translation result 'success' via o2if
  i2of match: saddr 10.0.0.2 sport 5201 daddr 20.0.0.1 dport 11570 proto TCP fib_idx 0 rewrite: saddr 192.168.160.101 sport 5201 daddr 20.0.0.2 dport 52558 
  o2if match: saddr 20.0.0.2 sport 52558 daddr 192.168.160.101 dport 5201 proto TCP fib_idx 0 rewrite: saddr 20.0.0.1 sport 11570 daddr 10.0.0.2 dport 5201 txfib 0 
  TCP state: closed
00:04:48:324594: ip4-lookup
  fib 0 dpo-idx 5 flow hash: 0x00000000
  TCP: 20.0.0.1 -> 10.0.0.2
    tos 0x00, ttl 64, length 60, checksum 0x1623 dscp CS0 ecn NON_ECN
    fragment id 0x0697, flags DONT_FRAGMENT
  TCP: 11570 -> 5201
    seq. 0xd803aaad ack 0x00000000
    flags 0x02 SYN, tcp header: 40 bytes
    window 64240, checksum 0x4ac6
    options:
      mss 1460, window scale -139065856, timestamp -139065856, echo/reflected timestamp, sack permitted
00:04:48:324597: ip4-rewrite
  tx_sw_if_index 1 dpo-idx 5 : ipv4 via 10.0.0.2 tap1: mtu:9000 next:4 flags:[] 02fe696ff93702fe051276900800 flow hash: 0x00000000
  00000000: 02fe696ff93702fe0512769008004500003c069740003f061723140000010a00
  00000020: 00022d321451d803aaad00000000a002faf04ac60000020405b40402
00:04:48:324599: tap1-output
  tap1 flags 0x00180005
  IP4: 02:fe:05:12:76:90 -> 02:fe:69:6f:f9:37
  TCP: 20.0.0.1 -> 10.0.0.2
    tos 0x00, ttl 63, length 60, checksum 0x1723 dscp CS0 ecn NON_ECN
    fragment id 0x0697, flags DONT_FRAGMENT
  TCP: 11570 -> 5201
    seq. 0xd803aaad ack 0x00000000
    flags 0x02 SYN, tcp header: 40 bytes
    window 64240, checksum 0x4ac6
    options:
      mss 1460, window scale -139065856, timestamp -139065856, echo/reflected timestamp, sack permitted
00:04:48:324601: tap1-tx
    buffer 0x9d232: current data 0, length 74, buffer-pool 0, ref-count 1, trace handle 0x11
                    l2-hdr-offset 0 l3-hdr-offset 14 
  hdr-sz 0 l2-hdr-offset 0 l3-hdr-offset 14 l4-hdr-offset 0 l4-hdr-sz 0
  IP4: 02:fe:05:12:76:90 -> 02:fe:69:6f:f9:37
  TCP: 20.0.0.1 -> 10.0.0.2
    tos 0x00, ttl 63, length 60, checksum 0x1723 dscp CS0 ecn NON_ECN
    fragment id 0x0697, flags DONT_FRAGMENT
  TCP: 11570 -> 5201
    seq. 0xd803aaad ack 0x00000000
    flags 0x02 SYN, tcp header: 40 bytes
    window 64240, checksum 0x4ac6
    options:
      mss 1460, window scale -139065856, timestamp -139065856, echo/reflected timestamp, sack permitted

Packet 19

00:04:48:324645: virtio-input
  virtio: hw_if_index 1 next-index 4 vring 0 len 74
    hdr: flags 0x00 gso_type 0x00 hdr_len 0 gso_size 0 csum_start 0 csum_offset 0 num_buffers 1
00:04:48:324649: ethernet-input
  frame: flags 0x1, hw-if-index 1, sw-if-index 1
  IP4: 02:fe:69:6f:f9:37 -> 02:fe:05:12:76:90
00:04:48:324654: ip4-input
  TCP: 10.0.0.2 -> 20.0.0.1
    tos 0x00, ttl 64, length 60, checksum 0x1cba dscp CS0 ecn NON_ECN
    fragment id 0x0000, flags DONT_FRAGMENT
  TCP: 5201 -> 11570
    seq. 0xf4b46973 ack 0xd803aaae
    flags 0x12 SYN ACK, tcp header: 40 bytes
    window 65160, checksum 0xab86
    options:
      mss 1460, window scale -139065856, timestamp -139065856, echo/reflected timestamp, sack permitted
00:04:48:324656: ip4-sv-reassembly-feature
  [not-fragmented]
00:04:48:324658: nat-pre-in2out
  in2out next_index 2 arc_next_index 10
00:04:48:324660: nat44-ed-in2out
  NAT44_IN2OUT_ED_FAST_PATH: sw_if_index 1, next index 10, session 1, translation result 'success' via i2of
  i2of match: saddr 10.0.0.2 sport 5201 daddr 20.0.0.1 dport 11570 proto TCP fib_idx 0 rewrite: saddr 192.168.160.101 sport 5201 daddr 20.0.0.2 dport 52558 
  o2if match: saddr 20.0.0.2 sport 52558 daddr 192.168.160.101 dport 5201 proto TCP fib_idx 0 rewrite: saddr 20.0.0.1 sport 11570 daddr 10.0.0.2 dport 5201 txfib 0 
  search key local 10.0.0.2:5201 remote 20.0.0.1:11570 proto TCP fib 0 thread-index 0 session-index 0
  TCP state: closed
00:04:48:324664: ip4-lookup
  fib 0 dpo-idx 4 flow hash: 0x00000000
  TCP: 192.168.160.101 -> 20.0.0.2
    tos 0x00, ttl 64, length 60, checksum 0xc5ac dscp CS0 ecn NON_ECN
    fragment id 0x0000, flags DONT_FRAGMENT
  TCP: 5201 -> 52558
    seq. 0xf4b46973 ack 0xd803aaae
    flags 0x12 SYN ACK, tcp header: 40 bytes
    window 65160, checksum 0xb45c
    options:
      mss 1460, window scale -139065856, timestamp -139065856, echo/reflected timestamp, sack permitted
00:04:48:324666: ip4-rewrite
  tx_sw_if_index 2 dpo-idx 4 : ipv4 via 20.0.0.2 tap2: mtu:9000 next:3 flags:[] 02fe7900b8be02feb984d0660800 flow hash: 0x00000000
  00000000: 02fe7900b8be02feb984d06608004500003c000040003f06c6acc0a8a0651400
  00000020: 00021451cd4ef4b46973d803aaaea012fe88b45c0000020405b40402
00:04:48:324668: tap2-output
  tap2 flags 0x00380005
  IP4: 02:fe:b9:84:d0:66 -> 02:fe:79:00:b8:be
  TCP: 192.168.160.101 -> 20.0.0.2
    tos 0x00, ttl 63, length 60, checksum 0xc6ac dscp CS0 ecn NON_ECN
    fragment id 0x0000, flags DONT_FRAGMENT
  TCP: 5201 -> 52558
    seq. 0xf4b46973 ack 0xd803aaae
    flags 0x12 SYN ACK, tcp header: 40 bytes
    window 65160, checksum 0xb45c
    options:
      mss 1460, window scale -139065856, timestamp -139065856, echo/reflected timestamp, sack permitted
00:04:48:324670: tap2-tx
    buffer 0x9f90b: current data 0, length 74, buffer-pool 0, ref-count 1, trace handle 0x12
                    natted l2-hdr-offset 0 l3-hdr-offset 14 
  hdr-sz 0 l2-hdr-offset 0 l3-hdr-offset 14 l4-hdr-offset 0 l4-hdr-sz 0
  IP4: 02:fe:b9:84:d0:66 -> 02:fe:79:00:b8:be
  TCP: 192.168.160.101 -> 20.0.0.2
    tos 0x00, ttl 63, length 60, checksum 0xc6ac dscp CS0 ecn NON_ECN
    fragment id 0x0000, flags DONT_FRAGMENT
  TCP: 5201 -> 52558
    seq. 0xf4b46973 ack 0xd803aaae
    flags 0x12 SYN ACK, tcp header: 40 bytes
    window 65160, checksum 0xb45c
    options:
      mss 1460, window scale -139065856, timestamp -139065856, echo/reflected timestamp, sack permitted

流量从远程主机发起,当NAT设备接收到SYN报文时,在out2in方向slow path处理节点生成了twice-nat的双向会话,会话如下:

代码语言:javascript
复制
 i2o 10.0.0.2 proto TCP port 5201 fib 0
    o2i 192.168.160.101 proto TCP port 5201 fib 0
       external host o2i 20.0.0.2:52558 i2o 20.0.0.1:11570
       i2o flow: match: saddr 10.0.0.2 sport 5201 daddr 20.0.0.1 dport 11570 proto TCP fib_idx 0 
           rewrite: saddr 192.168.160.101 sport 5201 daddr 20.0.0.2 dport 52558 
       o2i flow: match: saddr 20.0.0.2 sport 52558 daddr 192.168.160.101 dport 5201 proto TCP fib_idx 0 
          rewrite: saddr 20.0.0.1 sport 11570 daddr 10.0.0.2 dport 5201 txfib 0 
       index 1
       last heard 290.68
       timeout in 12.25
       total pkts 147, total bytes 117745
       static translation
       twice-nat

至此,我们已深入学习了两次NAT(Twice NAT)的基础配置知识。然而,在遵循官方指南配置iperf3进行测试时,遇到了连接无法成功建立的问题。在此过程中,我辨识出配置指南中可能存在两处误导之处,并已在文中详细阐述了这些疑点。尽管通过一系列调试,功能现已正常运行,并且测试结果与期望的两次NAT效果相吻合,我个人对于修改后的配置准确性仍持保留意见,缺乏完全的自信,需要和vpp官方予以确认。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DPDK VPP源码分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档