[新人报道][教程] Lala IEPL 使用 nftables 转发教程(低延迟)

前言

回答一下关于 nftablesiptables的问题,在lala群里面提问的。
下文可能简称 nftablesnft,iptablesipt

介绍下 nftablesiptables

先介绍下,nftablesiptables 都是linux下的netfilter用户态管理工具,底层都使用的是netfilter

###区别
nftables 相较于 iptables 更加的新颖和现代(吐槽: 虽然如此 nftables 也有着很多年了),iptables维护了四表五链,而nftables可以让用户自定义表,内部维护了一个虚拟机来操作netfiler。同时集合了ebtables,ip6tables,arptables等等,功能更加强大。
###相关链接
nftables iptables netfilter

nft与bbr

nftables是 Linux 内核转发,不进入用户态,也不开启 socket ,所以转发使用什么控制算法(bbr,cubic) 是无关的,与落地有关,落地开了 BBR 就可以享受到 BBR 加速。

如果你使用 socat/gost/realm 等 转发,不仅要看落地是否有 BBR 也要看专线是否有 BBR

教程

nftables端口转发

nftables支持直接写入文件的,只需要在文件头包含下面代码,这里我直接使用文件来描述后面教程了。

#!/usr/bin/nft -f

首先需要写一份nft文件, 通常是写在 /etc/nftables.conf文件里面。
第一次打开可能是这样。

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
        chain input {
                type filter hook input priority filter;
        }
        chain forward {
                type filter hook forward priority filter;
        }
        chain output {
                type filter hook output priority filter;
        }
}

这里我们可以直接使用现有的表来实现端口转发,你也可以自己写一个表。

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
		# 这三个链条如果你懂就可以动,不然就不动。
        chain input {
                type filter hook input priority filter;
        }
        chain forward {
                type filter hook forward priority filter;
        }
        chain output {
                type filter hook output priority filter;
        }
		# 首先处理 dnat
		chain port-dnat {
				type nat hook prerouting priority dstnat;policy accept;
				ip protocol { tcp,udp } th dport 这里写Lala入站端口 counter dnat to 这里写落地ip端口(例如: 12.34.56.78:9012)
		}

		# 再处理 snat
		chain port-snat {
				type nat hook postrouting priority srcnat;policy accept;
				ip daddr 落地ip(只有ip) masquerade
		}
}

写完过后执行下命令。

nft -f /etc/nftables.conf

这样过后就完成了正常转发了,对于其他小鸡,这样就可以实现端口转发了。
但是如果你使用 Lala这样的机器,还有一步需要做。

注意 : 上面的操作会使得nftables现有的规则清空,例如docker等可能会无法使用,需要在执行完毕过后重启。使用podman也需要重启。

lala转发的问题

使用过 Lala 家专线的都知道需要配置路由表,需要查看文档配置。
同时还需要持久化(教程使用的是corn@reboot时间的时候应用,可以用systemd配置其实,评论区补充)。
Lala家专线是不对称路由(具体是什么可以问ai),所以需要自己vnc手动配置下路由。

Q1: 为什么vnc可以用,但是ssh不能用。
A1: vnc是直接从虚拟机的tty输出了,不需要经过小鸡网络,只经过了Lala专线网关的网络。
Q2: 为什么不用 socat/gost/realm 之类的软件,简单方便。
A2: nft是内核态的转发,非用户态,严格意义上来说延迟更低(我相信大部分人都是跑转发的)。具体可以了解下计算机网络 TCP/IP
Q3: 为什么使用其他论坛大佬的`nftables`/`iptables` 无法使用。
A3: 因为是非对称路由。

还记得教程的配置吗,教程让创建了一个路由表,这里我拿移动的来举例。

echo "101 CM" >> /etc/iproute2/rt_tables
ip route add default via 192.168.47.1 dev eth0 table CM
ip rule add from 192.168.47.XX table CM

注意看,路由表的名称是 CM,因为路由问题,我们需要强制落地机的流量发到这个路由表,强制走 eth0这个网卡出去。使用下面的命令即可,

# 这里配置了 Linux 的策略路由,强制落地机的流量通过入口返回。
# 注意把 CM 替换成你配置的路由表,不同入口的 IEPL 不同。
ip rule add from 这里写落地机ip lookup CM 

这样一来,就可以使用 nftables 转发了。如果还想要添加多个落地机。
可以直接在刚才的 nftables文件写多条规则。

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
		# 这三个链条如果你懂就可以动,不然就不动。
        chain input {
                type filter hook input priority filter;
        }
        chain forward {
                type filter hook forward priority filter;
        }
        chain output {
                type filter hook output priority filter;
        }
		# 首先处理 dnat
		chain port-dnat {
				type nat hook prerouting priority dstnat;policy accept;
				ip protocol { tcp,udp } th dport 这里写Lala入站端口(一) counter dnat to 这里写落地ip端口(例如: 12.34.56.78:9012)(一)
				ip protocol { tcp,udp } th dport 这里写Lala入站端口(二) counter dnat to 这里写落地ip端口(例如: 12.34.56.78:9012)(二)
				ip protocol { tcp,udp } th dport 这里写Lala入站端口(三) counter dnat to 这里写落地ip端口(例如: 12.34.56.78:9012)(三)
		}
		set dst-ip {
			type ipv4_addr
			flags interval
			elements = {落地ip(一),落地ip(二),落地ip(三)} # 注意使用英文逗号分开
		}
		# 再处理 snat
		chain port-snat {
				type nat hook postrouting priority srcnat;policy accept;
				ip daddr @dst-ip  masquerade
		}
}

同时不要忘记配置策略路由。

ip rule add from 这里写落地机ip(一) lookup CM 
ip rule add from 这里写落地机ip(二) lookup CM 
ip rule add from 这里写落地机ip(三) lookup CM 

实际测试。

首先是去 itdog 测试,tcping 是可以通过的。

再测试延迟,我转发到 HKT ,是延迟能从250左右降低到150左右,好的时候有120,效果非常好。
速度可以自测,我测下来如果落地开bbr效果是差不多的。

尾序

今天上午才来到 Nodeseek ,之前没有账号,都是游客一直在看,现在有了 Nodeseek 号,可以更好的融入 Nodeseek 这个大论坛了。

如果大家对 nftables 感兴趣,我会在后面给大家写一篇教程,同时如果对 Grafana也感兴趣,也可以有教程,看多久有时间了。

最后请大家多给点鸡腿,收藏。

编辑后补充

#55 楼的方案更加清晰,同时易懂,如果会用 firewalld 的可以试试,但是不要忘记策略路由。

#48 楼指出了一个错误,如果你配置了过后无法打通可以试试这个楼的方案。同时这哥们写了一份简明的教程

另外,有些反馈如果配置了过后,会掉速度,现在具体原因未知,延迟是有降低的。

可能最大适合打游戏了。

点赞
  1. duckNet说道:

    这里发一下上文提到的,使用systemd 来开机配置路由

    Unit文件

    [Unit]
    Description=Auto Configure LALA net route set
    After=network.target  
    
    [Service]
    Type=oneshot
    ExecStart=/bin/sh -c "/usr/sbin/ip route add default via 192.168.47.1 dev eth0 table CM;/usr/sbin/ip rule add from 192.168.47.48 table CM"
    RemainAfterExit=yes 
    
    [Install]
    WantedBy=multi-user.target
    

    把 Exec 后面的命令自己替换成文档教程的参数。
    可以使用如下命令一键配置

    cat << EOF > /etc/systemd/system/route-auto-configure.service
    [Unit]
    Description=Auto Configure LALA net route set
    After=network.target  
    
    [Service]
    Type=oneshot
    # 这里记得自己配置
    # 这里记得自己配置
    # 这里记得自己配置
    ExecStart=/bin/sh -c "/usr/sbin/ip route add default via 192.168.47.1 dev eth0 table CM;/usr/sbin/ip rule add from 192.168.47.48 table CM"
    RemainAfterExit=yes 
    
    [Install]
    WantedBy=multi-user.target
    EOF
    systemctl daemon-reload
    systemctl enable route-auto-configure.service
    
  2. chacha20说道:

    firewalld底层默认使用nftables。这样写是等效的:

    要让firewalld转发生效需要三个条件,sysctl.conf中启用forwarding,
    firewall规则中启用伪装和转发。

    sysctl.conf我有洁癖不去修改它,而是写在这里(文件名随便写,目录必须是这里):/etc/sysctl.d/99-forwarding.conf

    net.ipv4.ip_forward = 1
    net.ipv6.conf.all.forwarding = 1
    net.ipv6.conf.default.forwarding = 1
    

    sysctl调优是核心,rmem和wmem要根据实际可用内存计算,还要填窗口存活期,balabala一堆,我写一个我自己用的(2G内存):

    vm.swappiness = 0
    fs.file-max = 1024000
    net.core.rmem_max = 134217728
    net.core.wmem_max = 134217728
    net.core.netdev_max_backlog = 250000
    net.core.somaxconn = 1024000
    net.core.default_qdisc = fq_pie
    net.ipv4.conf.all.rp_filter = 0
    net.ipv4.conf.default.rp_filter = 0
    net.ipv4.conf.lo.arp_announce = 2
    net.ipv4.conf.all.arp_announce = 2
    net.ipv4.conf.default.arp_announce = 2
    net.ipv4.ip_forward = 1
    net.ipv4.ip_local_port_range = 1024 65535
    net.ipv4.neigh.default.gc_stale_time = 120
    net.ipv4.tcp_ecn = 0
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_low_latency = 1
    net.ipv4.tcp_fin_timeout = 10
    net.ipv4.tcp_window_scaling = 1
    net.ipv4.tcp_keepalive_time = 10
    net.ipv4.tcp_timestamps = 0
    net.ipv4.tcp_sack = 1
    net.ipv4.tcp_fack = 1
    net.ipv4.tcp_syn_retries = 3
    net.ipv4.tcp_synack_retries = 3
    net.ipv4.tcp_max_syn_backlog = 16384
    net.ipv4.tcp_max_tw_buckets = 8192
    net.ipv4.tcp_fastopen = 3
    net.ipv4.tcp_mtu_probing = 1
    net.ipv4.tcp_rmem = 4096 87380 67108864
    net.ipv4.tcp_wmem = 4096 65536 67108864
    net.ipv4.tcp_congestion_control = bbr
    net.ipv6.conf.all.forwarding = 1
    net.ipv6.conf.default.forwarding = 1
    net.nf_conntrack_max = 25000000
    net.netfilter.nf_conntrack_max = 25000000
    net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30
    net.netfilter.nf_conntrack_tcp_timeout_established = 180
    net.netfilter.nf_conntrack_tcp_timeout_close_wait = 30
    net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 30
    

    好,正式开始配置规则,这里是日常运维的部分了(--permanent参数是持久化的意思,临时调试可以不用加,不加的话也不要执行覆盖命令firewall-cmd --reload

    #开启firewalld伪装和转发功能
    firewall-cmd --permanent --add-masquerade
    firewall-cmd --permanent --add-forward
    
    #转发规则1(接收11201端口的tcp+udp流量,转发到12.34.56.78地址的65201端口)
    firewall-cmd --permanent --zone=public --add-forward-port=port=11201:to-port=65201:to-addr=12.34.56.78:proto=tcp
    firewall-cmd --permanent --zone=public --add-forward-port=port=11201:to-port=65201:to-addr=12.34.56.78:proto=udp
    
    
    #转发规则2(接收11202端口的tcp+udp流量,转发到12.34.56.79地址的65202端口)
    firewall-cmd --permanent --zone=public --add-forward-port=port=11202:to-port=65201:to-addr=12.34.56.79:proto=tcp
    firewall-cmd --permanent --zone=public --add-forward-port=port=11202:to-port=65201:to-addr=12.34.56.79:proto=udp
    
    # 重载firewalld规则
    firewall-cmd --reload
    

    修改的话原始文件在/etc/firewald/zones/public.xml

    好了,再列一个我花了几天用gpt调教出来的一段脚本,可用的。别忘了使用前先配置好sysctl的forwarding参数

    #!/bin/bash
    
    # 定义规则列表
    # 如节点1,将流量从21011端口转发至12.34.56.78地址的65011端口,同时生成tcp+udp转发
    rules=(
        "节点1|21011|65011|12.34.56.78"
        "节点2|21012|65011|12.34.56.88"
        "节点3|21013|65011|12.34.56.98"
        "节点4|21014|65011|12.34.56.108"
        "节点5|21015|65011|12.34.56.118"
        "节点6|21016|65011|12.34.56.128"
        "节点7|21017|65011|12.34.56.138"
        "节点8|21018|65011|12.34.56.148"
    )
    
    # Step 0: 清空所有 forward-port 规则
    echo "Removing all existing forward-port rules..."
    while IFS= read -r port_rule; do
        if [[ -n "$port_rule" ]]; then
            # 去除可能存在的双引号
            clean_rule=$(echo "$port_rule" | sed 's/"//g')
            echo "Removing forward-port rule: $clean_rule"
            firewall-cmd --permanent --remove-forward-port="$clean_rule" -q
        fi
    done < <(firewall-cmd --list-forward-ports)
    
    # Step 1: 逐条添加 IPv4 规则
    echo "Adding new IPv4 forwarding rules..."
    for rule in "${rules[@]}"; do
        IFS='|' read -r name src_port to_port to_addr <<< "$rule"
        echo "Adding IPv4 forward rule for: $name"
        firewall-cmd --permanent --add-forward-port="port=$src_port:proto=tcp:toport=$to_port:toaddr=$to_addr" -q
        firewall-cmd --permanent --add-forward-port="port=$src_port:proto=udp:toport=$to_port:toaddr=$to_addr" -q
    done
    
    # Step 2: 添加 masquerade 规则(如果未添加)
    echo "Checking masquerade rules..."
    if ! firewall-cmd --query-masquerade -q; then
        echo "Adding masquerade rule..."
        firewall-cmd --permanent --add-masquerade -q
    fi
    
    # Step 3: 重新加载防火墙
    echo "Reloading firewall configuration..."
    firewall-cmd --reload -q
    
    # Step 4: 列出所有已配置的 forward-port 规则
    echo "Final configured forward-port rules:"
    firewall-cmd --list-forward-ports
    

回复 chacha20 取消回复

电子邮件地址不会被公开。必填项已用 * 标注

×
订阅图标按钮