尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Linux双网卡配置iptables NAT实现网络共享上网实战指南

Linux双网卡配置iptables NAT实现网络共享上网实战指南 1. 项目概述与核心价值最近在折腾一台老旧的工控机想把它改造成一个轻量级的家庭网络网关顺便给家里的智能设备提供一个隔离的网络环境。核心需求很简单这台机器有两张网卡一张eth0连接主路由能正常上网另一张eth1准备接一个交换机给其他设备用。目标就是让连接到eth1的设备能通过eth0共享上网。这个场景在小型办公室、实验室环境或者像我这样喜欢DIY网络的朋友那里非常常见。要实现这个目标核心就是启用Linux内核的NAT网络地址转换功能。听起来很高大上其实原理不复杂你可以把它想象成一个“翻译官”。内网设备比如192.168.2.100想访问外网比如访问百度它的请求包源地址是私有的192.168.2.100外网根本不认。这时候运行了NAT的Linux主机网关会把这个包的源地址“翻译”成自己外网网卡eth0的公网或上级局域网IP再发出去。回来的数据包网关再根据之前记录的“翻译记录”把目标地址“翻译”回内网设备的私有IP从而完成一次完整的通信。整个过程对内外网设备都是透明的。实现这个“翻译官”功能最经典、最直接的工具就是iptables。它是Linux内核防火墙Netfilter的用户空间管理工具功能极其强大规则链的设计也非常灵活。虽然现在有nftables作为新一代替代品但iptables凭借其广泛的认知度、丰富的资料和脚本兼容性在相当多的生产环境和像我这样的个人项目中依然是首选。通过几条简单的iptables规则我们就能轻松搭建起一个稳定可靠的双网卡共享上网环境。这个项目不仅实用更是理解Linux网络栈、数据包转发和防火墙策略的绝佳实践。2. 网络拓扑与前期准备2.1 典型双网卡网络拓扑在开始敲命令之前我们必须先理清网络结构这能避免后续很多配置上的混乱。我采用的是一种最典型、最清晰的拓扑结构[互联网] | [主路由器] (例如192.168.1.1) | | (网线) | [Linux主机 - eth0] (例如192.168.1.100/24, 网关: 192.168.1.1) | [Linux主机 - eth1] (例如192.168.2.1/24) | | (网线) | [交换机或AP] | |--------[客户端A] (例如192.168.2.100/24, 网关: 192.168.2.1) |--------[客户端B] (例如192.168.2.101/24, 网关: 192.168.2.1)在这个拓扑中eth0 (WAN侧)连接上级网络主路由需要从主路由的DHCP服务器获取IP或者手动配置一个与主路由同网段的静态IP如192.168.1.100。它的网关必须指向主路由192.168.1.1。这张网卡的任务是“对外”。eth1 (LAN侧)连接内部网络设备。我们需要为它手动配置一个静态IP地址这个地址将作为内网设备的网关。我选择了192.168.2.1/24这个网段纯粹是因为它和上级网络的192.168.1.0/24不同更容易在思维上区分内外。这张网卡的任务是“对内”。注意请务必确保你的两个网段不重叠。例如如果主路由是192.168.1.1那么内网就不要再使用192.168.1.0/24否则路由会发生混乱。常用的私有网段如10.0.0.0/8172.16.0.0/12192.168.0.0/16都可以选一个不冲突的即可。2.2 系统环境与网卡配置我使用的是一台安装Ubuntu Server 22.04 LTS的旧电脑。不同的Linux发行版在网卡命名和网络管理工具上可能略有差异例如CentOS 7的network-scripts Ubuntu的netplan但核心的iptables命令和内核参数是通用的。首先确认网卡识别情况ip link show或者用老命令ifconfig -a这会列出所有网络接口。记下你的两个物理网卡名称比如enp3s0和enp4s0或者传统的eth0和eth1。为了叙述方便我下文统一使用eth0外网和eth1内网。接下来配置IP地址。以Ubuntu 22.04使用netplan为例编辑配置文件sudo vim /etc/netplan/00-installer-config.yaml内容参考如下请根据你的实际网卡名修改network: version: 2 ethernets: eth0: dhcp4: true # 外网卡通常设为DHCP自动获取 optional: true eth1: addresses: [192.168.2.1/24] # 内网卡设置静态IP # 内网卡不需要配置网关和DNS因为它本身就要作为网关 optional: true应用配置sudo netplan apply对于使用NetworkManager或systemd-networkd的系统配置方式不同但目标一致让eth0能通外网让eth1有一个固定的内网IP。配置好后测试一下ping -c 4 192.168.1.1(通过eth0 ping主路由应该通)。ip addr show eth1(查看eth1是否成功配置了192.168.2.1)。2.3 开启内核IP转发功能这是最关键的一步但也是最容易被忽略的一步。默认情况下Linux内核出于安全考虑是禁止在不同网络接口之间转发IP数据包的。我们的网关角色要求它必须能转发包。临时开启重启失效sudo sysctl -w net.ipv4.ip_forward1永久开启需要编辑/etc/sysctl.conf文件sudo vim /etc/sysctl.conf找到或添加一行net.ipv4.ip_forward1然后使配置生效sudo sysctl -p验证是否开启成功sysctl net.ipv4.ip_forward如果返回net.ipv4.ip_forward 1则表示成功。实操心得很多朋友配置完iptables规则后发现内网还是上不了网十有八九是忘了开启IP转发。务必把这一步当作铁律在配置任何路由或NAT之前先检查它。3. iptables核心规则详解与配置iptables的规则是围绕“表”Table、“链”Chain和“规则”Rule组织的。对于我们实现NAT共享上网主要用到两个表filter过滤表和nat地址转换表。3.1 NAT表规则实现地址转换NAT表的核心是POSTROUTING链。我们需要在这里添加一条规则对所有从内网eth1发出经由本机转发到外网eth0的流量进行源地址转换SNAT或者使用更便捷的MASQUERADE动态伪装。方法一使用 MASQUERADE推荐用于动态IP外网如果你的eth0IP是动态获取的比如DHCPMASQUERADE是首选。它会自动使用eth0当前的IP地址作为伪装源地址。sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE-t nat指定操作nat表。-A POSTROUTING在POSTROUTING链末尾追加规则。POSTROUTING链是数据包即将离开本机之前经过的链在这里做SNAT最合适。-o eth0匹配输出接口为eth0的包。-o代表--out-interface。-j MASQUERADE跳转到MASQUERADE目标即执行IP伪装动作。方法二使用 SNAT适用于静态IP外网如果你的eth0是固定IP例如192.168.1.100可以使用SNAT性能稍好且更精确。sudo iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o eth0 -j SNAT --to-source 192.168.1.100-s 192.168.2.0/24匹配源地址属于192.168.2.0/24这个内网段的包。--to-source 192.168.1.100将这些包的源地址修改为192.168.1.100。注意事项MASQUERADE会带来轻微的性能开销因为它需要为每个连接额外处理。但在家庭或小型网络环境中这点开销完全可以忽略不计其便利性远胜于SNAT。我强烈建议初学者和动态IP环境使用MASQUERADE。3.2 Filter表规则设置转发策略光有NAT还不够防火墙默认是拒绝所有转发的。我们需要在filter表的FORWARD链中放行相关的流量。基本放行规则允许已建立连接和相关连接通过 这是保证网络畅通的基础规则应该放在最前面。sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT-m conntrack启用连接跟踪模块。这是实现有状态防火墙的关键它能识别一个数据包是属于某个已建立的连接还是一个新的连接请求。--ctstate RELATED,ESTABLISHED匹配状态为RELATED与已有连接相关如FTP的数据连接或ESTABLISHED已建立的连接的数据包。-j ACCEPT接受这些包。这条规则至关重要它确保了内网设备发起的请求其返回的响应数据包能够顺利通过防火墙回到内网。放行内网到外网的转发请求sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT-i eth1匹配输入接口为eth1内网卡的包。-o eth0匹配输出接口为eth0外网卡的包。这条规则的意思是允许从内网进来要从外网出去的包进行转发。这对应了内网设备访问互联网的请求。可选放行外网到内网的特定转发 默认情况下我们通常不允许从外网主动发起到内网的连接这是安全的基本要求。但如果你需要内网提供某些服务如Web服务器给外网访问就需要配置端口转发DNAT并在FORWARD链中放行。这是一个进阶话题基础共享上网可以暂时不配置这条。3.3 规则保存与持久化通过上面几条命令配置的iptables规则是保存在内存中的重启系统就会丢失。我们必须将其保存到文件中并设置开机自动加载。保存当前规则 在Ubuntu/Debian上可以使用iptables-persistent包。sudo apt update sudo apt install iptables-persistent -y安装过程中它会询问你是否保存当前的IPv4和IPv6规则选择“是”即可。之后规则会被保存到/etc/iptables/rules.v4和/etc/iptables/rules.v6。你也可以手动保存和加载# 保存规则到文件 sudo iptables-save /etc/iptables/rules.v4 # 从文件加载规则 sudo iptables-restore /etc/iptables/rules.v4设置开机自启 安装了iptables-persistent后它会自动创建systemd服务netfilter-persistent.service来实现开机加载规则。你可以检查服务状态sudo systemctl status netfilter-persistent对于其他发行版如CentOS/RHEL通常将iptables-save的输出重定向到/etc/sysconfig/iptables然后通过systemctl enable iptables来启用服务。踩坑记录我曾经在配置完一切后发现重启后网络又断了排查半天才发现是忘了持久化规则。另一个坑是在某些使用firewalld的系统如新版CentOS上iptables服务可能被禁用或冲突。你需要先停止并禁用firewalldsudo systemctl stop firewalld sudo systemctl disable firewalld再安装启用iptables-services。务必确认你的系统用的是哪种防火墙管理工具。4. 客户端配置与连通性测试4.1 内网客户端网络配置Linux网关配置好后内网的其他设备客户端需要做相应设置才能通过它上网。以Windows客户端为例打开“控制面板” - “网络和共享中心” - “更改适配器设置”。右键点击你的有线或无线网卡选择“属性”。双击“Internet协议版本 4 (TCP/IPv4)”。选择“使用下面的IP地址”IP地址192.168.2.100(可以是192.168.2.2到192.168.2.254之间任意一个确保不重复)子网掩码255.255.255.0默认网关192.168.2.1(这就是你的Linux网关的内网IP)首选DNS服务器可以设置为你的Linux网关IP192.168.2.1也可以设置为公共DNS如223.5.5.5或8.8.8.8。如果设成网关需要在网关上配置DNS转发例如安装dnsmasq。以Linux客户端为例使用netplan# /etc/netplan/01-client.yaml network: version: 2 ethernets: eth0: addresses: [192.168.2.100/24] routes: - to: default via: 192.168.2.1 # 网关指向Linux主机 nameservers: addresses: [192.168.2.1, 223.5.5.5] # DNS服务器4.2 分层测试与故障排查配置完成后不要急着打开浏览器应该进行分层测试精准定位问题。第一步测试客户端到网关的连通性在客户端上执行ping 192.168.2.1如果不通检查物理链路网线、交换机/AP是否正常客户端IP配置IP、掩码是否正确是否和网关在同一网段网关的eth1接口ip addr show eth1确认IP配置正确且接口是UP状态。防火墙临时关闭网关上的iptables(sudo iptables -F) 再试如果通了说明是FORWARD链规则有问题。第二步测试网关到外网的连通性在Linux网关上执行ping -c 4 223.5.5.5如果不通检查eth0的IP和网关ip route show default确认默认网关指向正确的主路由IP。主路由的DHCP或静态分配是否正常。网关的DNS解析nslookup www.baidu.com。第三步测试客户端通过网关的NAT转发在客户端上执行# 先ping一个外网IP排除DNS问题 ping -c 4 223.5.5.5 # 再ping一个域名测试DNS转发 ping -c 4 www.baidu.com如果第一步通第二步通但第三步不通问题很可能出在网关的IP转发或iptables规则上。在网关上使用关键诊断命令确认IP转发已开启再次强调sysctl net.ipv4.ip_forward查看配置的iptables规则sudo iptables -t nat -L -v -n # 查看NAT表规则关注POSTROUTING链 sudo iptables -L FORWARD -v -n # 查看FILTER表的FORWARD链规则检查MASQUERADE或SNAT规则是否存在以及FORWARD链的放行规则计数器(pkts和bytes)是否有在增加。如果计数器一直是0说明规则没有匹配到流量。使用连接跟踪查看NAT状态sudo conntrack -L当客户端尝试访问外网时这里应该能看到从内网IP到外网地址的连接跟踪条目并且带有[ASSURED]标记。这是证明NAT正在工作的最直接证据。使用tcpdump抓包分析 这是终极排查手段。在网关的两个接口上分别抓包看数据包走到哪一步消失了。# 在eth1内网侧抓包看请求是否到达网关 sudo tcpdump -i eth1 -n icmp or port 53 # 在eth0外网侧抓包看请求是否被转发出去 sudo tcpdump -i eth0 -n icmp or port 53例如在客户端ping223.5.5.5时你应该在eth1上看到来自客户端IP的ICMP请求包在eth0上看到源地址被伪装成eth0IP的ICMP请求包。如果eth1有包而eth0没有问题就出在转发或NAT环节。5. 进阶配置与优化基础功能实现后我们可以考虑一些增强配置让这个网关更安全、更好用。5.1 为内网客户端提供DHCP与DNS服务手动配置每个客户端的IP非常麻烦。我们可以安装dnsmasq这个轻量级软件它同时提供DHCP和DNS缓存转发功能。安装sudo apt install dnsmasq -y配置前先备份并编辑其配置文件sudo cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak sudo vim /etc/dnsmasq.conf找到并修改或添加以下关键配置# 指定监听的内网接口 interfaceeth1 # 禁止监听lo回环和eth0外网 no-dhcp-interfacelo,eth0 # 设置DHCP地址池、租期、网关和DNS dhcp-range192.168.2.100,192.168.2.200,255.255.255.0,12h dhcp-optionoption:router,192.168.2.1 dhcp-optionoption:dns-server,192.168.2.1,223.5.5.5 # 启用DNS缓存并指定上游DNS服务器 cache-size1000 server223.5.5.5 server8.8.8.8重启dnsmasq并设置开机自启sudo systemctl restart dnsmasq sudo systemctl enable dnsmasq现在内网客户端只需设置为“自动获取IP地址”就能从网关获得IP、网关和DNS信息实现“插网线就能上网”。5.2 配置端口转发DNAT如果你内网有一台IP为192.168.2.50的Web服务器端口80希望从外网能访问它就需要用到目的地址转换DNAT也就是端口转发。在Linux网关上添加iptables规则# 1. 在nat表的PREROUTING链做DNAT sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.2.50:80 # 2. 在filter表的FORWARD链放行这条转发的流量 sudo iptables -A FORWARD -i eth0 -o eth1 -p tcp -d 192.168.2.50 --dport 80 -j ACCEPT第一条规则将到达eth0外网端口8080的TCP连接目标地址改写为内网服务器的192.168.2.50:80。第二条规则允许这条被转发的流量通过防火墙。这样外网用户访问http://你的网关外网IP:8080时请求就会被转发到内网的Web服务器上。5.3 基础安全加固规则默认的转发规则比较宽松。我们可以添加一些基础的安全规则。限制内网IP范围在FORWARD链的放行规则中可以更精确地指定源IP段。sudo iptables -I FORWARD 2 -s 192.168.2.0/24 -i eth1 -o eth0 -j ACCEPT # -I FORWARD 2 表示在FORWARD链的第二条位置插入放在状态检测规则之后设置默认转发策略为DROP谨慎操作sudo iptables -P FORWARD DROP这条命令会将FORWARD链的默认策略设置为DROP拒绝。这意味着只有我们明确ACCEPT的规则匹配的包才能被转发其他一律拒绝。在执行此命令前务必确保你的ACCEPT规则已经正确配置否则会导致网络立即中断。对于生产环境这是推荐做法对于实验环境可以保持默认的ACCEPT以便调试。防止常见的网络攻击可选增加规则# 防止SYN洪水攻击 sudo iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT # 限制新建连接速率 sudo iptables -A FORWARD -p tcp --syn -m connlimit --connlimit-above 30 -j DROP5.4 规则管理与维护脚本规则多了之后手动管理容易出错。可以编写一个简单的Shell脚本用于快速应用、清空或备份规则。创建一个脚本文件例如/usr/local/bin/firewall-setup.sh#!/bin/bash IPTABLES/sbin/iptables case $1 in start) echo Setting up firewall and NAT... # 刷新所有规则清空 $IPTABLES -F $IPTABLES -t nat -F $IPTABLES -t mangle -F $IPTABLES -X # 删除用户自定义链 # 设置默认策略FORWARD链设为ACCEPT以便调试生产环境可设为DROP $IPTABLES -P INPUT ACCEPT $IPTABLES -P FORWARD ACCEPT $IPTABLES -P OUTPUT ACCEPT $IPTABLES -t nat -P PREROUTING ACCEPT $IPTABLES -t nat -P POSTROUTING ACCEPT $IPTABLES -t nat -P OUTPUT ACCEPT # 1. 设置NAT (MASQUERADE) $IPTABLES -t nat -A POSTROUTING -o eth0 -j MASQUERADE # 2. 设置Filter表转发规则 # 允许已建立/相关的连接 $IPTABLES -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # 允许内网到外网的转发 $IPTABLES -A FORWARD -s 192.168.2.0/24 -i eth1 -o eth0 -j ACCEPT # 可选端口转发示例将外网8080转到内网80 # $IPTABLES -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.2.50:80 # $IPTABLES -A FORWARD -i eth0 -o eth1 -p tcp -d 192.168.2.50 --dport 80 -j ACCEPT echo Firewall rules applied. ;; stop) echo Stopping firewall (setting all policies to ACCEPT and flushing rules)... $IPTABLES -P INPUT ACCEPT $IPTABLES -P FORWARD ACCEPT $IPTABLES -P OUTPUT ACCEPT $IPTABLES -t nat -P PREROUTING ACCEPT $IPTABLES -t nat -P POSTROUTING ACCEPT $IPTABLES -t nat -P OUTPUT ACCEPT $IPTABLES -F $IPTABLES -t nat -F $IPTABLES -t mangle -F $IPTABLES -X echo Firewall stopped. ;; save) echo Saving current rules to /etc/iptables/rules.v4... sudo iptables-save | sudo tee /etc/iptables/rules.v4 /dev/null echo Rules saved. ;; status) echo NAT Table sudo iptables -t nat -L -v -n echo -e \n Filter Table FORWARD Chain sudo iptables -L FORWARD -v -n ;; *) echo Usage: $0 {start|stop|save|status} exit 1 ;; esac给脚本添加执行权限sudo chmod x /usr/local/bin/firewall-setup.sh之后就可以通过sudo firewall-setup.sh start/stop/save/status来方便地管理规则了。记得在修改规则后执行save命令来持久化。6. 常见问题与深度排查实录即使按照步骤操作也可能会遇到各种问题。这里记录几个我踩过的坑和对应的排查思路。6.1 客户端能ping通网关但无法上网现象客户端可以ping 192.168.2.1但ping 223.5.5.5或访问网页失败。排查步骤检查网关的IP转发这是最常见的原因。运行sysctl net.ipv4.ip_forward确认是1。检查iptables规则运行sudo iptables -L FORWARD -v -n和sudo iptables -t nat -L POSTROUTING -v -n。查看规则计数器是否有增加。如果没有可能是规则顺序或匹配条件有问题。尝试在FORWARD链最前面插入一条临时放行所有转发的规则用于测试sudo iptables -I FORWARD 1 -j ACCEPT。如果此时客户端能上网了再仔细检查你原来的FORWARD规则。检查网关的路由表运行ip route show。确保有默认路由default via ... dev eth0。确保没有错误的路由指向了eth1。在网关上进行跟踪路由在网关上执行traceroute 223.5.5.5看数据包是否能正常到达外网。如果不能问题出在网关自身的出站连接上而不是转发。使用conntrack工具在客户端发起一个访问外网的请求如curl http://www.baidu.com同时在网关运行sudo conntrack -L | grep 192.168.2.100替换为你的客户端IP。如果能看到相关的连接跟踪条目说明NAT和转发在起作用问题可能出在客户端的DNS或应用层。6.2 NAT规则不生效或计数器不增加现象sudo iptables -t nat -L -v -n命令中MASQUERADE规则的pkts和bytes始终为0。可能原因与解决数据包没有到达POSTROUTING链NAT规则只在数据包经过nat表时才生效。如果数据包在更早的环节比如路由决策就被丢弃或发往本地进程了就不会触发NAT。确保客户端流量确实是需要转发的流量。可以用tcpdump在eth1抓包确认请求的目的IP是外网IP而不是网关自身IP。规则匹配条件过于严格检查你的MASQUERADE或SNAT规则中的-o eth0是否写对了网卡名。如果流量从其他接口出去就不会匹配。使用-o eth或-o ppp可以匹配一类接口但不够精确。连接跟踪conntrack的影响iptables是有状态的。如果一个连接的首包因为某些规则被拒绝后续即使添加了允许规则该连接的数据包也可能因为连接跟踪状态而被直接丢弃。可以尝试清空连接跟踪表sudo conntrack -F然后让客户端重试。6.3 网络性能不佳或延迟高现象内网设备上网速度慢延迟大。排查与优化硬件瓶颈老旧电脑的网卡可能是百兆的或者CPU性能孱弱无法胜任高速NAT转发。使用iftop或nload查看网络吞吐量使用top或htop查看CPU使用率特别是在高速下载时。MTU问题这是一个经典问题。如果外网是PPPoE常见于家庭宽带其MTU通常是1492字节。而内网以太网MTU是1500字节。如果网关没有正确处理MTU会导致TCP数据包被分片降低效率甚至引起连接问题。解决方案是在网关的eth0外网口上设置MTU为1492或你的宽带实际MTUsudo ip link set dev eth0 mtu 1492并考虑在iptables的FORWARD链上添加规则为TCP连接设置MSS最大报文段长度sudo iptables -t mangle -A FORWARD -o eth0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1452iptables规则效率规则链过长、规则顺序不合理会影响转发性能。尽量将匹配频率高的规则放在前面。使用-m state老版本或-m conntrack新版本的状态匹配规则效率很高应优先使用。6.4 重启后所有配置丢失现象配置好后一切正常但重启Linux主机后网络共享失效。解决这是没有做好配置持久化的典型表现。确保iptables规则已保存使用sudo iptables-save /etc/iptables/rules.v4命令并确认文件内容正确。确保iptables-persistent服务已启用sudo systemctl is-enabled netfilter-persistent应返回enabled。检查启动加载顺序极少数情况下网络接口在iptables规则加载时还未准备好。可以考虑将加载iptables规则的命令写入网络启动后的脚本中例如在/etc/network/if-up.d/目录下创建一个脚本。但对于大多数使用netfilter-persistent或iptables-services的系统这不是必须的。检查IP转发设置是否持久化确认/etc/sysctl.conf中有net.ipv4.ip_forward1并且执行过sudo sysctl -p。经过以上步骤一个由Linux双网卡主机担当的、基于iptablesNAT的共享网络网关就应该能稳定运行了。这个方案虽然不如专业路由器功能丰富但它给了我们极大的灵活性和控制权是学习网络知识和构建定制化网络环境的绝佳起点。
返回列表