惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
L
LINUX DO - 热门话题
Blog — PlanetScale
Blog — PlanetScale
博客园 - Franky
J
Java Code Geeks
腾讯CDC
博客园 - 聂微东
The Cloudflare Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 司徒正美
Last Week in AI
Last Week in AI
量子位
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Google DeepMind News
Google DeepMind News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
S
Schneier on Security
C
CERT Recently Published Vulnerability Notes
Latest news
Latest news
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
有赞技术团队
有赞技术团队
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Securelist
AWS News Blog
AWS News Blog
GbyAI
GbyAI
L
LINUX DO - 最新话题
大猫的无限游戏
大猫的无限游戏
Forbes - Security
Forbes - Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Attack and Defense Labs
Attack and Defense Labs
C
CXSECURITY Database RSS Feed - CXSecurity.com
Y
Y Combinator Blog
W
WeLiveSecurity
T
Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
P
Proofpoint News Feed
D
DataBreaches.Net
博客园 - 三生石上(FineUI控件)
V
V2EX
N
News and Events Feed by Topic
Google DeepMind News
Google DeepMind News
D
Docker
The Hacker News
The Hacker News
A
About on SuperTechFans
Security Latest
Security Latest
NISL@THU
NISL@THU
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
博客园_首页
H
Hacker News: Front Page

蛮荆

如何获取更多的免费服务器 Kubernetes 调度器队列 - 设计与实现 Kubernetes 调度器 - 核心流程 Kubernetes Networking Model & CNI Kubernetes 控制器管理总结 Kubernetes CronJob 设计与实现 Kubernetes Job 设计与实现 Kubernetes HPA 设计与实现 Kubernetes Deployment 滚动更新实现原理 Kubernetes GC 设计与实现 Kubernetes Pod 驱逐 - 设计与实现 Kubernetes Daemonset 设计与实现 Kubernetes ReplicaSet 设计与实现 Kubernetes EndPoint 设计与实现 Kubernetes Informer 设计与实现 降本增效之应用优化 (三) 日志存储与检索 Kubernetes Pod 设计与实现 - 创建流程 Kubernetes 探针设计与实现 Unix 编程艺术名句摘录 Kubernetes - CRI 概述 Golang 编译速度为什么这么快? Kubernetes Pod 设计与实现 - Pause 容器 Kubernetes - kube-proxy 代理模式工程优化 Kubernetes 应用最佳实践 - 优雅关闭长连接 Kubernetes Service 类型和会话亲和性 Kubernetes 为什么需要 Ingress Kubernetes 架构 - 控制平面和数据平面 降本增效之应用优化 (二) 大报表 Go 语言如何获取 CPU 利用率 降本增效之应用优化 (一) Redis 业务规则引擎演变过程简述 微服务中的熔断算法 漏桶算法和令牌桶算法 jsonparser 为什么比标准库的 encoding/json 快 10 倍 ? zap 高性能设计与实现 HTTP Router 算法演进 fastcache 高性能设计与实现 Web 常见的三个安全问题 ants Code Reading Go 线程安全 map 方案选型 布隆过滤器 死锁、活锁、饥饿、自旋锁 sync.Pool Code Reading Go 内存管理概述 Go netpoll Code Reading goroutine 泄漏与检测 time/Timer Code Reading GMP Scheduler Code Reading Go channel 的 15 条规则和底层实现 为什么 Linux “一切皆文件” context.Context Code Reading runtime/HACKING.md Goland 最佳实践 互联网开发与金庸武学 为什么 Redis 6.0 引入多线程模型? Kubernetes 应用最佳实践 - 金丝雀发布 容器中如何正确配置 GOMAXPROCS ? singleflight Code Reading sync.Map Code Reading sync.Cond Code Reading sync.WaitGroup Code Reading sync.RWMutex Code Reading sync.Mutex Code Reading sync.Once Code Reading Go 无锁编程 sync/atomic Code Reading goroutine 交替打印奇偶数 GODEBUG Go 并发模式 Go 汇编 UUID 通用技术选型 Kubernetes 应用最佳实践 - 水平自动伸缩 Go 高性能 Tips fasthttp 为什么比标准库 net/http 快 10 倍 ? 技术文章配图指南 ChatGPT 初体验 Docker 网络原理概览 iptables 的五表五链 Kubernetes 应用最佳实践 - 亲和性和污点容忍度 Go 的反射与三大定律 Docker 官方提供的最佳实践 Go 语言内置的设计模式 HTTP1 到 HTTP3 的工程优化 Kubernetes 应用最佳实践 - Sidecar 模式 Kubernetes 应用最佳实践 - init 容器和钩子函数 为什么 recover 必须在 defer 中调用? 为什么 defer 的执行顺序和注册顺序不同? Go map 设计与实现 Go 切片扩容底层实现 Go 语言中的零拷贝 Go Delve 云原生和边缘计算简介 Kubernetes Pod 服务质量等级 Kubernetes 应用最佳实践 - 探针 Kubernetes 应用最佳实践 - 资源请求和限制 CDN 原理 Kubernetes 应用最佳实践 - 开篇 缓存策略和模式 Go 内存模型 Kubernetes 核心概念
网络基础: NAT 是如何工作的 ?
2018-02-10 · via 蛮荆

2018-02-10 计算机网络

  • 什么是 NAT ?
    • 主要功能
    • 为什么需要 NAT ?
  • 实现类型
    • 1. 静态 NAT
    • 2. 动态 NAT
    • 3. NAPT
  • 地址转换类型
    • SNAT
    • DNAT
    • 双向地址转换
  • 实现原理示例
    • 私有 (内网) 地址向公网地址发送数据包
    • 公网地址向私有 (内网) 地址发送数据包
  • NAT 设备支持端口数量上限
  • NAT 和 iptables
  • 扩展阅读

什么是 NAT ?

NAT(Network Address Translation,网络地址转换) 是一种网络技术,通过重写 IP 数据包的 {源 IP 地址} 或者 {目标 IP 地址} 信息,被普遍用来解决 “公网 IP 地址短缺” 的问题。

主要功能

将内部网络 (如企业或居民住宅) 的私有 IP 地址转换为公网 IP 地址,从而允许多个内部主机/设备共享一个公网 IP 地址与外部网络 (一般指互联网) 进行通信。

图片来源: 网络是怎样连接的(户根勤)

为什么需要 NAT ?

  1. 缓解 公网 IPv4 地址短缺问题 (最主要的原因)
  2. 提高网络安全性,NAT 通过隐藏内部网络的 IP 地址结构,外部用户无法直接访问内部网络设备 (透明代理)
  3. 私有 IP 地址可以灵活扩展,不同的私有地址可以在不同的内部网络中使用 (例如 A 公司的某台服务器和 B 公司的某台客户端具有相同的 IP 地址,这是完全 OK 的,因为这两个设备之间不会进行通信)

当然,NAT 同时也存在一些不足 (缺点):

  1. 资源开销:NAT 设备需要维护大量的地址转换信息
  2. 协议兼容性:一些应用层协议(如 SIP、IPSec)流量可能无法穿越 NAT 设备,需要额外的配置或技术来解决
  3. 性能:由于每个数据包都需要进行地址转换,会对网络性能产生一定的影响
  4. 限制: NAT 受限于未被占用的端口号数量

实现类型

既可以在支持网络地址转换的路由器(称为 NAT 网关)中配置 NAT,也可以在 Linux 服务器中配置 NAT(Linux 服务器实际上充当的是 “软件路由器” 的角色)。

NAT 根据实现方式分为三类:

1. 静态 NAT

内网 IP 与公网 IP 是一对一的永久映射关系。

例如:内部地址 192.168.1.10 映射到公网地址 203.0.113.10。

2. 动态 NAT

内网 IP 从公网 IP 池中,动态选择一个进行映射。

例如:多个内部地址 192.168.1.10, 192.168.1.11 等可以动态映射到公网地址池中的 203.0.113.10, 203.0.113.11 等。

3. NAPT

网络地址端口转换 NAPT(Network Address and Port Translation),目前主流的 NAT 实现方式,目标是为了更有效地利用公网 IP 地址 (一个公网 IP 应该服务于尽可能多的内部 IP),现代的 NAT 转换表把传输层的端口号也加上了,这样多个内部的主机/设备就一个共用一个公网 IP, 一般将 NAPT 简称为 “地址转换表”。

NAPT 地址转换表示例


地址转换类型

在描述 NAT 的技术实现原理之前,首先来介绍几个专业术语。

SNAT

SNAT(Source Network Address Translation)主要用于转换数据包中的源 IP 地址,目标 IP 地址保持不变,主要目标是隐藏内部网络中设备的私有 IP 地址,并将其转换为一个公网 IP 地址。

应用场景:多个内网 IP 地址共享一个公网 IP 地址。

   PACKET FORWARDED                     PACKET RECEIVED
|----------------------|             |----------------------|
|    IP PACKET         |             |    IP PACKET         |
|                      |             |                      |
| SRC: 192.168.0.2     |             | SRC: 100.100.100.100 |
| DST: 123.125.115.110 |             | DST: 123.125.115.110 |
| |---------------|    |             | |---------------|    |
| |   TCP PACKET  |    | = (SNAT) => | |   TCP PACKET  |    |
| | DPORT: 80     |    |             | | DPORT: 80     |    |
| | SPORT: 2345   |    |             | | SPORT: 3456   |    |
| | ... DATA ...  |    |             | | ... DATA ...  |    |
| |---------------|    |             | |---------------|    |
|----------------------|             |----------------------|

DNAT

DNAT (Destination Network Address Translation) 主要用于转换数据包中的目标 IP 地址,源 IP 地址保持不变,主要目标是将 公网 IP 地址的请求重定向到内部网络的特定网络设备。

应用场景:将外部请求重定向到内部服务器,同时隐藏外部请求对应的后端服务器的真实 IP 地址。

   PACKET RECEIVED                      PACKET FORWARDED
|----------------------|             |----------------------|
|    IP PACKET         |             |    IP PACKET         |
|                      |             |                      |
| SRC: 123.125.115.110 |             | SRC: 123.125.115.110 |
| DST: 100.100.100.100 |             | DST: 192.168.0.2     |
| |---------------|    |             | |---------------|    |
| |   TCP PACKET  |    | = (DNAT) => | |   TCP PACKET  |    | 
| | DPORT: 3456   |    |             | | DPORT: 2345   |    |
| | SPORT: 80     |    |             | | SPORT: 80     |    |
| | ... DATA ...  |    |             | | ... DATA ...  |    |
| |---------------|    |             | |---------------|    |
|----------------------|             |----------------------|

双向地址转换

同时使用 SNAT 和 DNAT,当接收到网络包时,执行 DNAT,把目标 IP 转换为内部 IP;而在发送网络包时,执行 SNAT,把源 IP 替换为外部 IP。

下面通过一个小例子来说明,为了便于演示,这里省略 NAT 网关中的端口映射关系。

地址转换类型

  1. 内部主机 (IP: 192.168.0.2) 访问 http://baidu.com (123.125.115.110)
  2. NAT 网关会把源 IP 地址 (192.168.0.2) 转换成自己的公网 IP (100.100.100.100),然后发送给 http://baidu.com
  3. baidu.com 收到请求后,发送响应
  4. NAT 网关接收到 baidu.com 的响应数据包后,将目标 IP 地址转换成内部 IP 地址 (192.168.0.2),发送给内部对应的主机

实现原理示例

NAT 的基本原理是在转发网络包时,对 IP 头部中四元组的 (源 IP, 目标 IP, 源端口,目标端口) 进行改写。

下面通过一个具体的小例子,来说明 NAT 的工作原理。

私有 (内网) 地址向公网地址发送数据包

假设这里的 NAT 转换工作是由网关来完成的,其中 (NAT 网关) 公网 IP + 端口号 <=> 私有 IP + 端口号 的映射关系如下图所示,当然,这个映射关系也就是 地址转换表.

现在私有 IP 10.10.1.1 要通过端口 1025 向公网 IP 192.0.2.7980 端口发送数据,其中,NAT 网关的 IP 为 198.18.8.31

图片来源: 网络是怎样连接的(户根勤)

  1. 私有 IP 10.10.1.1 通过端口 1025 发送数据包
  2. SNAT: 网关通过地址转换表,将数据包中的源 IP 改写为自身 IP 198.18.8.31, 源端口改写为私有地址的映射端口 5436
  3. 公网 IP 192.0.2.7980 端口接收到数据包后,进行响应的处理,然后向网关 IP 198.18.8.31 的端口 5436 发送数据包
  4. DNAT: 网关接收到数据包后,通过地址转换表,将数据包中的目标 IP 改写为私有 IP 10.10.1.1, 目标端口改写为私有地址的端口 1025

公网地址向私有 (内网) 地址发送数据包

整个过程和 私有地址向公网地址发送数据包 类似,这不过是网关的 SNAT, DNAT 工作顺序整好相反,这里不再赘述,感兴趣的读者可以参考下图进行推导。

图片来源: 网络是怎样连接的(户根勤)


NAT 设备支持端口数量上限

💡 网络连接 {五元组} 对于 NAT 设备依然适用。

NAT 设备最多可以支持的端口号映射数量取决于:

  1. 端口数量:NAT 设备可以使用的端口号范围从 1 到 65535,其中一些端口号(如 0-1023)通常保留用于特权服务(如 HTTP、HTTPS、FTP 等),因此可用的端口号大约在 1024 到 65535 之间,这样实际可用的端口号大约有 64511 个。

  2. IP 地址数量:如果 NAT 设备只有一个公有 IP 地址,那么它最多可以映射约 64511 个端口。但如果设备有多个公有 IP 地址,每个 IP 地址都可以使用约 64511 个端口号,支持的端口映射数量可以组合增加。例如,如果 NAT 设备有 10 个公有 IP 地址,那么它可以支持的端口映射数量大约是 10 × 64511 = 645110 个。

  3. 设备性能和内存:虽然理论上可以支持这么多的端口号映射,但实际情况中,NAT 设备的硬件性能(CPU、内存)和软件实现也会限制其实际支持的连接数。

如果某个内网主机向公网服务端发起了大量连接,例如 10 万连接,这会占用 NAT 设备的大量端口号资源。

假设 NAT 设备有两个公有 IP 地址(203.0.113.1 和 203.0.113.2),每个 IP 地址最多支持 64511 个端口,并且负载均衡策略为轮询,那么连接端口映射情况如下:

  • 为 203.0.113.1 分配 50000 个连接
  • 为 203.0.113.2 分配 50000 个连接

NAT 和 iptables

iptables 中的 NAT 表 用于实现网络地址转换,包含 3 种内置链:

  • PREROUTING
  • POSTROUTING
  • OUTPUT

iptables 的基本语法命令格式:

iptables [-t 表名] 管理选项 [链名] [匹配条件] [-j 控制类型]

通过 iptables 实现流量转发,将目标 IP 地址为 192.168.1.1 + 目标端口为 27017 的所有 TCP 数据包转发到 10.0.0.2:1234

iptables \
  -A PREROUTING    # 追加一条规则到 PREROUTING 链,常用于 DNAT
  -t nat           # 用于 nat 表
  -p tcp           # 这条规则仅适用于 TCP 数据包
  -d 192.168.1.1   # 这条规则仅适用于目标 IP 地址为 192.168.1.1 的数据包
  --dport 27017    # 这条规则仅适用于目标端口为 27017 的数据包
  -j DNAT          # 指定目标网络地址转换
  --to-destination # 指定转发的目标地址为 10.0.0.2:1234
     10.0.0.2:1234 

下面是流量转发的示意图,因为是 DNAT, 所以源 IP 地址和源端口在转发过程中不会发生变化。

   PACKET RECEIVED                   PACKET FORWARDED
|---------------------|           |---------------------|
|    IP PACKET        |           |    IP PACKET        |
|                     |           |                     |
| SRC: 192.168.1.2    |           | SRC: 192.168.1.2    |
| DST: 192.168.1.1    |           | DST: 10.0.0.2       |
| |---------------|   |           | |---------------|   |
| |   TCP PACKET  |   | =(DNAT)=> | |   TCP PACKET  |   |
| | DPORT: 27017  |   |           | | DPORT: 1234   |   |
| | SPORT: 23456  |   |           | | SPORT: 23456  |   |
| | ... DATA ...  |   |           | | ... DATA ...  |   |
| |---------------|   |           | |---------------|   |
|---------------------|           |---------------------|

更多 iptables 技术原理和使用方法可以参考 这篇文章


扩展阅读