专栏/[Linux软路由第二弹] - 5.设置PPPoE拨号和防火墙

[Linux软路由第二弹] - 5.设置PPPoE拨号和防火墙

2022年11月24日 06:11--浏览 · --点赞 · --评论
粉丝:812文章:35

1.设置PPPoE

在上一篇文章《 [Linux软路由第二弹] - 4.设置基础网络和系统参数 》中,Linux 路由器已经初步就绪,现在开始设置PPPoE拨号以及防火墙。

在上版构建 Linux 路由器的文章中,使用了 pppoeconf 工具来创建拨号配置。

但该工具已多年未更新,导致其设置 PPPoE 拨号的配置文件为 /etc/network/interfaces 。

这与当前使用 Systemd Network 进行网络配置的方式不太一致。

因此,本文以创建 systemd 服务的方式来进行 PPPoE 拨号。

1.1.创建拨号配置文件

PPPoE 拨号的主配置文件一般位于 /etc/ppp/peers 目录下。

配置文件名可自定义,演示值为 serverwan 。

使用 nano 编辑器创建 PPPoE拨号 配置文件,执行以下命令:

## 创建 PPPoE拨号 配置文件
sudo nano /etc/ppp/peers/serverwan

在编辑器对话框中输入以下内容,并保存。

注意:配置文件中 mtu 参数默认值为 1492 ,这个参数与运营商相关,请根据实际情况进行调整。

# This configuration file is customized by fox
# Optimize PPPoE dialing parameters
# The mtu parameter is optional, default is 1492

# Set PPPoE user name
user "<your_pppoe_user_name>"

# MTU default is 1492
mtu 1480

# Other adjustable parameters
+ipv6
default-asyncmap
defaultroute
hide-password
noaccomp
noauth
noipdefault
persist

PPPoE 拨号的密码配置文件一般位于 /etc/ppp 目录下。

使用 nano 编辑器编辑 PPPoE密码 配置文件,执行以下命令:

## 编辑 CHAP 认证 PPPoE密码 配置文件
sudo nano /etc/ppp/chap-secrets

注意:如果拨号失败,可能运营商不支持 CHAP 加密认证,则尝试改用 PAP 认证:

## 编辑 PAP 认证 PPPoE密码 配置文件
sudo nano /etc/ppp/pap-secrets

在编辑器对话框中输入以下内容,并保存:

# Secrets for authentication using CHAP/PAP
# client	server	secret			IP addresses
"<your_pppoe_user_name>" * "<your_pppoe_user_password>"

使用以下命令对密码配置文件的权限进行修正:

## 修正 CHAP 认证文件权限
sudo chmod 600 /etc/ppp/chap-secrets

注意:当使用 PAP 认证时,则改用以下命令:

## 修正 PAP 认证文件权限
sudo chmod 600 /etc/ppp/pap-secrets

1.2.创建拨号服务

根据之前的内容,用于拨号的物理网口为 enp6s18 ,拨号配置文件名为 serverwan 。

在创建 PPPoE systemd 拨号服务的过程中会用到这两个参数,请根据实际情况进行调整。

拨号服务命名规则:

pppd-<physical_port_name>@<pppoe_name>.service

因此本文中演示服务名为:

pppd-enp6s18@serverwan.service

使用 nano 编辑器创建 PPPoE服务 配置文件,执行以下命令:

## 创建 PPPoE服务 配置文件
sudo nano /etc/systemd/system/pppd-enp6s18@serverwan.service

在编辑器对话框中输入以下内容,并保存:

[Unit]
Description=PPP connection for %I
Documentation=man:pppd(8)
BindsTo=sys-subsystem-net-devices-%j.device
After=sys-subsystem-net-devices-%j.device
After=network.target
Before=default.target

[Service]
Type=notify
ExecStartPre=/lib/systemd/systemd-networkd-wait-online -i %j -o carrier
ExecStart=/usr/sbin/pppd plugin rp-pppoe.so %j call %i linkname %i ifname pppoe-out1 up_sdnotify
ExecStop=/bin/kill $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
StandardOutput=null
Restart=always
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=strict
ReadWritePaths=/run/ /etc/ppp/
ProtectControlGroups=yes
SystemCallFilter=~@mount
SystemCallArchitectures=native
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes

[Install]
WantedBy=sys-devices-virtual-net-%i.device
WantedBy=default.target

由于修改了服务项,需要使用以下命令进行重载:

## 服务重载
sudo systemctl daemon-reload

使用以下命令让 PPPoE 拨号服务开机自启动:

## 设置 PPPoE 拨号服务开机自启
sudo systemctl enable pppd-enp6s18@serverwan.service

由于现在防火墙暂未设置,不建议现在启动服务进行拨号,以避免安全隐患。

如果后续使用中,PPPoE 拨号服务出现异常,使用以下命令进行检查:

## 检查 PPPoE 拨号服务
sudo journalctl -eu pppd-enp6s18@serverwan.service

1.3.配置拨号接口

由于拨号服务可能意外退出,为了在服务重启后能再次拿到 IPv6 地址,需要对拨号接口进行调整。

使用 nano 编辑器创建 拨号接口 配置文件,执行以下命令:

## 创建 拨号接口 配置文件
sudo nano /etc/systemd/network/75-pppoe.network

在编辑器对话框中输入以下内容,并保存。

注意:cake 部分为 QoS 参数,请根据实际情况进行调整。

[Match]
Name=pppoe-out1
Type=ppp

[Network]
LLMNR=no

[IPv6AcceptRA]
DHCPv6Client=always
UseDNS=no

[CAKE]
Bandwidth=50M
OverheadBytes=38
MPUBytes=84
UseRawPacketSize=yes
FlowIsolationMode=triple
NAT=yes
PriorityQueueingPreset=diffserv4

[Link]
RequiredForOnline=no

如果后续使用过程中,遇到系统启动缓慢,使用以下命令进行检查:

## 查看系统启动时间分布
sudo systemd-analyze blame

## 检查导致启动缓慢的服务
sudo systemd-analyze critical-chain systemd-networkd-wait-online.service

## 检查网络配置情况
sudo networkctl status -a

2.设置防火墙

在上版构建 Linux 路由器的文章中,使用了 iptables 进行防火墙配置,以及 iptables-restore 对防火墙进行持久化。

但 OpenWrt 从 22.03 版本开始,防火墙后端不再使用 iptables ,取而代之的是 nftables 。

当然,不仅 OpenWrt 有这样的变化,其他 Linux 发行版也有类似的情况,具体原因请查阅 Netfilter 官网相关信息。

因此,本文中防火墙配置工具同步变更为 nftables ,防火墙命令从 OpenWrt 22.03.2 版本中导出。

主要修改有:

  • 默认启用 flowtable ,并对监听接口进行修改(OpenWrt 的 flowtable 监听了端口 pppoe-wan )

  • 默认禁止外网 IPv4 / IPv6 对本机的 Echo Request

  • 防火墙默认行为从 reject 变更为 drop

  • 定义了内网 DNS 服务器组,非组内 IP 的 DNS 请求将重定向到本机

  • 访问光猫的网口与PPPoE接口共享防火墙策略,简化防火墙命令

根据内核相关文档 Netfilter’s flowtable infrastructure 中的描述:

Since Linux kernel 5.13, the flowtable infrastructure discovers the real netdevice behind VLAN and PPPoE netdevices. The flowtable software datapath parses the VLAN and PPPoE layer 2 headers to extract the ethertype and the VLAN ID / PPPoE session ID which are used for the flowtable lookups. The flowtable datapath also deals with layer 2 decapsulation.

You do not need to add the PPPoE and the VLAN devices to your flowtable, instead the real device is sufficient for the flowtable to track your flows.

考虑到 OpenWrt 22.03 内核版本为 5.10.* ,Ubuntu Server 22.10 内核版本为 5.19.* ,因此将 PPPoE 拨号后生成的端口从 flowtable 中移除是个更好的选择,这样不仅能向前兼容,还能解决 nftables 服务与 PPPoE拨号 服务启动顺序带来的冲突。

配置防火墙之前,需要检查 nftables.service 服务状态,确保该服务开机自启动。

## 检查 nftables.service
sudo systemctl status nftables.service

前文提过,服务状态为 enabled; preset: enabled ,表示该服务已开机自启动。

而当前服务实际状态为 disabled; preset: enabled ,则表示该服务并未开机自启动:

## 示例输出
○ nftables.service - nftables
     Loaded: loaded (/lib/systemd/system/nftables.service; disabled; preset: enabled)
     Active: inactive (dead)
       Docs: man:nft(8)
             http://wiki.nftables.org

执行以下命令,将该服务设置为开机自启动:

## 设置 nftables.service 开机自启动
sudo systemctl enable nftables.service

nftables.service 启动时会自动加载 /etc/nftables.conf 配置文件 ,也就是防火墙的默认配置。

修改防火墙设置之前,使用以下命令将其备份:

## 备份 nftables 配置文件
sudo mv /etc/nftables.conf /etc/nftables.conf.bak

使用 nano 编辑器创建 nftables 配置文件,执行以下命令:

## 创建新的 nftables 配置文件
sudo nano /etc/nftables.conf

注意:在应用防火墙配置之前请仔细阅读防火墙命令条目,并根据实际情况修改以下内容

  • 访问光猫网口名称,演示值为:enp6s18

  • flowtable 包含的网口,演示值为:enp6s18, enp6s19, enp6s20, enp6s21, enp6s22

  • 网桥接口名称,演示值为:bridge1

  • PPPoE 接口名称,演示值为:pppoe-out1

  • 内网 DNS 服务器组,除了本机地址(演示值为 172.16.1.1 、 fd10::1 ),其余均可自定义或移除

#!/usr/sbin/nft -f

# This configuration file is customized by fox
# Optimize system nftables for linux router

flush ruleset

table inet router {
	#
	# Flowtable
	#

	flowtable ft {
		hook ingress priority filter;
		devices = { enp6s18, enp6s19, enp6s20, enp6s21, enp6s22 };
	}


	#
	# Defines
	#

	define local_dns_ipv4 = { 172.16.1.1, 172.16.1.2, 172.16.1.3 }
	define local_dns_ipv6 = { fd10::1, fd10::2, fd10::3 }


	#
	# Filter rules
	#

	chain input {
		type filter hook input priority filter; policy accept;
		iifname "lo" accept comment "defconf: Accept traffic from loopback"
		ct state established,related accept comment "defconf: Allow inbound established and related flows"
		ct state invalid counter drop comment "defconf: Drop flows with invalid conntrack state"
		tcp flags & (fin | syn | rst | ack) == syn counter jump syn_flood comment "defconf: Rate limit TCP syn packets"
		iifname "bridge1" jump input_lan comment "defconf: Handle lan IPv4/IPv6 input traffic"
		iifname { "enp6s18", "pppoe-out1" } jump input_wan comment "defconf: Handle wan IPv4/IPv6 input traffic"
	}

	chain forward {
		type filter hook forward priority filter; policy drop;
		meta l4proto { tcp, udp } flow offload @ft comment "defconf: Track forwarded flows"
		ct state established,related accept comment "defconf: Allow forwarded established and related flows"
		ct state invalid counter drop comment "defconf: Drop flows with invalid conntrack state"
		iifname "bridge1" jump forward_lan comment "defconf: Handle lan IPv4/IPv6 forward traffic"
		iifname { "enp6s18", "pppoe-out1" } jump forward_wan comment "defconf: Handle wan IPv4/IPv6 forward traffic"
	}

	chain output {
		type filter hook output priority filter; policy accept;
		oifname "lo" accept comment "defconf: Accept traffic towards loopback"
		ct state established,related accept comment "defconf: Allow outbound established and related flows"
		ct state invalid counter drop comment "defconf: Drop flows with invalid conntrack state"
		oifname "bridge1" jump output_lan comment "defconf: Handle lan IPv4/IPv6 output traffic"
		oifname { "enp6s18", "pppoe-out1" } jump output_wan comment "defconf: Handle wan IPv4/IPv6 output traffic"
	}

	chain prerouting {
		type filter hook prerouting priority filter; policy accept;
		iifname "bridge1" jump helper_lan comment "defconf: Handle lan IPv4/IPv6 helper assignment"
	}

	chain handle_reject {
		meta l4proto tcp reject with tcp reset comment "defconf: Reject TCP traffic"
		counter reject comment "defconf: Reject any other traffic"
	}

	chain syn_flood {
		limit rate 25/second burst 50 packets return comment "defconf: Accept SYN packets below rate-limit"
		counter drop comment "defconf: Drop excess packets"
	}

	chain input_lan {
		ct status dnat counter accept comment "lanconf: Accept port redirections"
		jump accept_from_lan
	}

	chain output_lan {
		jump accept_to_lan
	}

	chain forward_lan {
		jump accept_to_wan comment "defconf: Accept lan to wan forwarding"
		ct status dnat counter accept comment "lanconf: Accept port forwards"
		jump accept_to_lan
	}

	chain helper_lan {
	}

	chain accept_from_lan {
		iifname "bridge1" counter accept comment "defconf: Accept lan IPv4/IPv6 traffic"
	}

	chain accept_to_lan {
		oifname "bridge1" counter accept comment "defconf: Accept lan IPv4/IPv6 traffic"
	}

	chain input_wan {
		meta nfproto ipv4 udp dport 68 counter accept comment "defconf: Allow-DHCP-Renew"
		meta nfproto ipv4 icmp type echo-request counter drop comment "defconf: Drop-ICMP-Ping-Input"
		meta nfproto ipv6 icmpv6 type echo-request counter drop comment "defconf: Drop-ICMPv6-Ping-Input"
		meta nfproto ipv4 meta l4proto igmp counter accept comment "defconf: Allow-IGMP"
		meta nfproto ipv6 udp dport 546 counter accept comment "defconf: Allow-DHCPv6"
		ip6 saddr fe80::/10 icmpv6 type . icmpv6 code { mld-listener-query . no-route, mld-listener-report . no-route, mld-listener-done . no-route, mld2-listener-report . no-route } counter accept comment "defconf: Allow-MLD"
		meta nfproto ipv6 icmpv6 type { destination-unreachable, time-exceeded, echo-request, echo-reply, nd-router-solicit, nd-router-advert } limit rate 100/second counter accept comment "defconf: Allow-ICMPv6-Input"
		meta nfproto ipv6 icmpv6 type . icmpv6 code { packet-too-big . no-route, parameter-problem . no-route, nd-neighbor-solicit . no-route, nd-neighbor-advert . no-route, parameter-problem . admin-prohibited } limit rate 100/second counter accept comment "defconf: Allow-ICMPv6-Input"
		jump drop_from_wan
	}

	chain output_wan {
		jump accept_to_wan
	}

	chain forward_wan {
		meta nfproto ipv6 icmpv6 type echo-request counter drop comment "defconf: Drop-ICMPv6-Ping-Forward"
		meta nfproto ipv6 icmpv6 type { destination-unreachable, time-exceeded, echo-request, echo-reply } limit rate 100/second counter accept comment "defconf: Allow-ICMPv6-Forward"
		meta nfproto ipv6 icmpv6 type . icmpv6 code { packet-too-big . no-route, parameter-problem . no-route, parameter-problem . admin-prohibited } limit rate 100/second counter accept comment "defconf: Allow-ICMPv6-Forward"
		meta l4proto esp counter jump accept_to_lan comment "defconf: Allow-IPSec-ESP"
		udp dport 500 counter jump accept_to_lan comment "defconf: Allow-ISAKMP"
		jump drop_to_wan
	}

	chain accept_to_wan {
		oifname { "enp6s18", "pppoe-out1" } counter accept comment "defconf: Accept wan IPv4/IPv6 traffic"
	}

	chain drop_from_wan {
		iifname { "enp6s18", "pppoe-out1" } counter drop comment "defconf: Drop wan IPv4/IPv6 traffic"
	}

	chain drop_to_wan {
		oifname { "enp6s18", "pppoe-out1" } counter drop comment "defconf: Drop wan IPv4/IPv6 traffic"
	}


	#
	# NAT rules
	#

	chain dstnat {
		type nat hook prerouting priority dstnat; policy accept;
		iifname "bridge1" meta l4proto { tcp, udp } th dport domain counter jump dstnat_lan comment "!fw4: Handle lan IPv4/IPv6 dstnat traffic"
	}

	chain srcnat {
		type nat hook postrouting priority srcnat; policy accept;
		oifname { "enp6s18", "pppoe-out1" } jump srcnat_wan comment "defconf: Handle wan IPv4/IPv6 srcnat traffic"
	}

	chain dstnat_lan {
		ip saddr $local_dns_ipv4 meta l4proto { tcp, udp } th dport domain counter accept comment "lanconf: Accept lan dns IPv4 bootstrap query"
		ip6 saddr $local_dns_ipv6 meta l4proto { tcp, udp } th dport domain counter accept comment "lanconf: Accept lan dns IPv6 bootstrap query"
		meta l4proto { tcp, udp } th dport domain counter redirect to domain comment "lanconf: Lan dns redirect"
	}

	chain srcnat_wan {
		meta nfproto ipv4 masquerade comment "defconf: Masquerade IPv4 wan traffic"
	}


	#
	# Raw rules (notrack)
	#

	chain raw_prerouting {
		type filter hook prerouting priority raw; policy accept;
	}

	chain raw_output {
		type filter hook output priority raw; policy accept;
	}


	#
	# Mangle rules
	#

	chain mangle_prerouting {
		type filter hook prerouting priority mangle; policy accept;
	}

	chain mangle_postrouting {
		type filter hook postrouting priority mangle; policy accept;
	}

	chain mangle_input {
		type filter hook input priority mangle; policy accept;
	}

	chain mangle_output {
		type route hook output priority mangle; policy accept;
	}

	chain mangle_forward {
		type filter hook forward priority mangle; policy accept;
		iifname { "enp6s18", "pppoe-out1" } tcp flags syn tcp option maxseg size set rt mtu comment "defconf: Zone wan IPv4/IPv6 ingress MTU fixing"
		oifname { "enp6s18", "pppoe-out1" } tcp flags syn tcp option maxseg size set rt mtu comment "defconf: Zone wan IPv4/IPv6 egress MTU fixing"
	}

}

至此,服务器 PPPoE 拨号以及防火墙设置步骤完成。

投诉或建议