在树莓派上使用 VPN 的 Linux 路由器

来自 Alpine Linux

原理

本指南演示了如何设置带有 VPN 隧道的 Linux 路由器。您将需要第二个以太网适配器。如果您正在使用 Raspberry Pi,那么您可以使用类似 Apple USB 以太网适配器 这样的设备,因为它包含 ASIX AX88772,后者具有良好的 Linux 支持。

您也可以选择购买 实时时钟[死链接]。如果您没有 RTC,则当您的 Pi 关闭时,时间会丢失。当它重新启动时,时间将设置回 1970 年 1 月 1 日星期四。由于这比您的 VPN 证书的创建时间早,OpenVPN 将拒绝启动,这可能意味着您无法通过 VPN 进行 DNS 查找。

对于无线网络,购买了单独的接入点 (Ubiquiti UniFi AP),因为它包含 Atheros AR9287,后者受 ath9k 支持。

我选择 Raspberry Pi 是因为它价格便宜。我并不关心获得高 PPS (每秒数据包数)。您可以选择使用旧的 x86/amd64 系统来代替。如果我的互联网更好,我可能会选择 Soekris 🔓 的产品,例如 net6501 🔓,因为它比通用的 x86_64 桌面处理器具有更低的功耗。

如果您想路由速度高于 100 Mbit/s,您将需要使用硬件加密,例如 AES-NI。Soekris 产品可以选择额外的硬件加密模块 (vpn1411[死链接])。另一个选择是使用 Mini ITX 主板,以及托管交换机。我选择了 Ubiquiti ES-16-150W

如果您希望使用 IPv6,您应该考虑查看 在树莓派上使用 VPN 的 Linux 路由器 (IPv6),因为其实现方式与本教程略有不同。

本教程中的网络看起来像这样

Network Diagram Single IPv4
网络图 单个 IPv4

安装

本指南假定您正在 ramdisk 模式下从 micro SD 卡使用 Alpine Linux。它假定您已经阅读了有关如何使用 Alpine 本地备份 的基础知识。Raspberry Pi 文章包含有关如何在 Raspberry Pi 上安装 Alpine Linux 的信息。

全桥接模式的调制解调器

此特定页面使用了一个示例,其中您的调制解调器使用 PPPoE。您需要修改不适用于您的部分。

在本例中,我有一个已配置为全桥接模式的调制解调器。PPP 会话在路由器上发起。

我正在使用的调制解调器是 Cisco 877 集成服务路由器。它没有 Web 界面,而是通过 SSH 进行控制。更多信息可以在 配置 Cisco 877 为全桥接模式 中找到。

网络

/etc/hostname

将其设置为您的主机名,例如

<HOST_NAME>

/etc/hosts

设置您的主机和主机名

127.0.0.1	<HOST_NAME> <HOST_NAME>.<DOMAIN_NAME>

::1		<HOST_NAME> ipv6-gateway ipv6-loopback
ff00::0		ipv6-localnet
ff00::0		ipv6-mcastprefix
ff02::1		ipv6-allnodes
ff02::2		ipv6-allrouters
ff02::3		ipv6-allhosts

/etc/network/interfaces

配置您的网络接口。将“yourISP”更改为 /etc/ppp/peers/yourISP 中文件的文件名

#
# Network Interfaces
#

# Loopback interfaces
auto lo
iface lo inet loopback
  address 127.0.0.1
  netmask 255.0.0.0

# Internal Interface - facing LAN
auto eth0
iface eth0 inet static
  address 192.168.1.1
  netmask 255.255.255.0
  broadcast 192.168.1.255


PPP

接下来,您需要配置路由器,使其能够与调制解调器拨号 PPP 连接。

如果您的 ISP 使用 PPP,您可能需要对其进行配置。请参阅 PPP

您需要确保设置 WAN 接口,在本例中我们使用了 eth1。

# External Interface - facing Modem
allow-hotplug eth1
auto eth1
iface eth1 inet static
  address 192.168.0.2
  netmask 255.255.255.252
  broadcast 192.168.0.3
  pre-up /sbin/ip link set eth1 up
  up ifup ppp0=yourISP
  down ifdown ppp0=yourISP
  post-down /sbin/ip link set eth1 up

# Link to ISP
iface yourISP inet ppp
  provider yourISP

IPoE

或者,ISP 使用 IPoE 也非常常见。IPoE 更简单,仅在外部接口上运行 DHCP。它应该看起来像这样

# External interface to ISP
allow-hotplug eth1
auto eth1
iface eth1 inet dhcp

iface eth1 inet static
    address 192.168.0.2
    netmask 255.255.255.252
    broadcast 192.168.0.3

iface eth1 inet6 manual

来自 ISP 的 DHCP

上面我们设置了 DHCP 并设置了静态 IP。这样做是为了我们仍然可以将数据包转发到调制解调器,以便能够访问 Web 界面或 SSH。

我们仍然需要 DHCP 才能从 ISP 获取 IP 地址。我喜欢使用 dhcpcd 而不是 udhcp(Alpine Linux 中的默认设置),因为它允许 前缀委派,这在 IPv6 网络中使用。

我的 /etc/dhcpcd.conf 看起来像这样

# Enable extra debugging
# debug
# logfile /var/log/dhcpcd.log

# Allow users of this group to interact with dhcpcd via the control
# socket.
#controlgroup wheel

# Inform the DHCP server of the hostname for DDNS.
hostname gateway

# Use the hardware address of the interface for the Client ID.
# clientid
# or
# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as
# per RFC4361. Some non-RFC compliant DHCP servers do not reply with
# this set. In this case, comment out duid and enable clientid above.
duid

# Persist interface configuration when dhcpcd exits.
persistent

# Rapid commit support.
# Safe to enable by default because it requires the equivalent option
# set on the server to actually work.
option rapid_commit

# A list of options to request from the DHCP server.
option domain_name_servers, domain_name, domain_search, host_name
option classless_static_routes

# Most distributions have NTP support.
option ntp_servers

# Respect the network MTU.
# Some interface drivers reset when changing the MTU so disabled by
# default.
#option interface_mtu 1586

# A ServerID is required by RFC2131.
require dhcp_server_identifier

# Generate Stable Private IPv6 Addresses instead of hardware based
# ones
slaac private

# A hook script is provided to lookup the hostname if not set by the
# DHCP server, but it should not be run by default.
nohook lookup-hostname

# Disable solicitations on all interfaces
noipv6rs

# Wait for IP before forking to background
waitip 6

# Don't touch DNS
nohook resolv.conf

allowinterfaces eth1 eth0.2
# Use the interface connected to WAN
interface eth1
    waitip 4
    noipv4ll
    ipv6rs # enable routing solicitation get the default IPv6 route
    iaid 1
    ia_pd 1/::/56 eth0.2/2/64
    timeout 30

interface eth0.2
    ipv6only

带有路由的基本 IPtables 防火墙

这演示了如何设置具有宽松出站防火墙的基本路由。传入数据包被阻止。其余部分在规则集中注释。

首先安装 iptables

apk add iptables

注意: 如果您使用的 Alpine 版本早于 3.19.0,另请安装 ip6tables
#########################################################################
# Basic iptables IPv4 routing rule set
#
# 192.168.1.0/24 routed directly to PPP0 via NAT
# 
#########################################################################

#
# Mangle Table
# We leave this empty for the moment.
#
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT

#
# Filter Table
# This is where we decide to ACCEPT, DROP or REJECT packets
#
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
*filter

# Create rule chain per input interface for forwarding packets
:FWD_ETH0 - [0:0]
:FWD_ETH1 - [0:0]
:FWD_PPP0 - [0:0]

# Create rule chain per input interface for input packets (for host itself)
:IN_ETH0 - [0:0]
:IN_ETH1 - [0:0]
:IN_PPP0 - [0:0]

# Create a log drop chain
:LOG_DROP - [0:0]

# Pass input packet to corresponding rule chain
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth0 -j IN_ETH0
-A INPUT -i eth1 -j IN_ETH1
-A INPUT -i ppp0 -j IN_PPP0

# Pass forwarded packet to corresponding rule chain
-A FORWARD -i eth0 -j FWD_ETH0
-A FORWARD -i eth1 -j FWD_ETH1
-A FORWARD -i ppp0 -j FWD_PPP0

# Forward LAN traffic out
-A FWD_ETH0 -s 192.168.1.0/24 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Forward SSH packets from network to modem
-A FWD_ETH1 -s 192.168.0.0/30 -d 192.168.1.0/24 -p tcp -m tcp --sport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Forward HTTP to modem's webserver
-A FWD_ETH1 -s 192.168.0.0/30 -d 192.168.1.0/24 -p tcp -m tcp --sport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Forward traffic to ISP
-A FWD_PPP0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# SSH to Router
-A IN_ETH0 -s 192.168.1.0/24 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# DNS to Router
-A IN_ETH0 -s 192.168.1.0/24 -p tcp -m tcp --dport 1812 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# FreeRadius Client (eg a UniFi AP)
-A IN_ETH0 -s 192.168.1.0/24 -p udp -m udp --dport 1812 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# NTP to Router
-A IN_ETH0 -s 192.168.1.0/24 -p udp -m udp --dport 123 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Accept traffic
-A IN_ETH0 -s 192.168.1.0/24 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# SSH To Modem from Router
-A IN_ETH1 -s 192.168.0.1/32 -d 192.168.0.0/30 -p tcp -m tcp --sport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# HTTP to modem
-A IN_ETH1 -s 192.168.0.1/32 -d 192.168.0.0/30 -p tcp -m tcp --sport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Accept incoming tracked PPP0 connection
-A IN_PPP0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
COMMIT

#
# NAT Table
# This is where translation of packets happens as well as "forwarding" of ports
# to specific hosts.
#
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Port forwarding for Bittorrent
-A PREROUTING -i ppp0 -p tcp -m tcp --dport 6881:6889 -j DNAT --to-destination 192.168.1.20
-A PREROUTING -i ppp0 -p udp -m udp --dport 6881:6889 -j DNAT --to-destination 192.168.1.20

# Allows routing to our modem subnet so we can access the web interface or SSH
-A POSTROUTING -s 192.168.1.0/24 -d 192.168.0.1/32 -o eth1 -p tcp -m tcp --dport 22 -j MASQUERADE
-A POSTROUTING -s 192.168.1.0/24 -d 192.168.0.1/32 -o eth1 -p tcp -m tcp --dport 80 -j MASQUERADE

# Allows hosts of the network to use the PPP tunnel
-A POSTROUTING -s 192.168.1.0/24 -o ppp0 -j MASQUERADE
COMMIT

如果您是 iptables 新手,我还强烈建议阅读这些资源

/etc/sysctl.d/local.conf

# Controls IP packet forwarding
net.ipv4.ip_forward = 1

# Needed to use fwmark, only required if you want to set up the VPN subnet later in this article
net.ipv4.conf.all.rp_filter = 2

# Disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

请注意,此处禁用了 IPv6,如果您想要使用 IPv6,请参阅另一个教程 在树莓派上使用 VPN 的 Linux 路由器 (IPv6)。您可能还希望查看 ip-sysctl.txt 以阅读有关其他键的信息。

DHCP

apk add dhcp

/etc/conf.d/dhcpd

指定配置文件位置、要运行的接口以及您希望 DHCPD 在 IPv4 模式下运行。

# /etc/conf.d/dhcpd: config file for /etc/init.d/dhcpd

# If you require more than one instance of dhcpd, you can create symbolic
# links to dhcpd service like so
#   cd /etc/init.d
#   ln -s dhcpd dhcpd.foo
#   cd ../conf.d
#   cp dhcpd dhcpd.foo
# Now you can edit dhcpd.foo and specify a different configuration file.
# You'll also need to specify a pidfile in the dhcpd.conf file.
# See the pid-file-name option in the dhcpd.conf man page for details.

# If you wish to run dhcpd in a chroot environment, uncomment the following line
# DHCPD_CHROOT="/var/lib/dhcp/chroot"

# All file paths below are relative to the chroot.
# You can specify a different chroot directory, but MAKE SURE it's empty.

# Specify a configuration file - the default is /etc/dhcp/dhcpd.conf
DHCPD_CONF="/etc/dhcp/dhcpd.conf"

# Configure which interface or interfaces to for dhcpd to listen on.
# List all interfaces space separated. If this is not specified then
# we listen on all interfaces.
DHCPD_IFACE="eth0"

# Insert any other dhcpd options. See the man page for a full list.
DHCPD_OPTS="-4"

/etc/dhcp/dhcpd.conf

配置您的 DHCP 配置服务器。对于我的 DHCP 服务器,我将有三个子网。每个子网都有特定的用途。您可以选择拥有任意数量的子网,如下所示。如果您使用了 VLAN,则 broadcast-address 将有所不同。但是,在本例中未使用 VLAN。

authoritative;
ddns-update-style interim;

shared-network home {
  subnet 192.168.1.0 netmask 255.255.255.0 {
    range 192.168.1.10 192.168.1.240;
    option subnet-mask 255.255.255.0;
    option broadcast-address 192.168.1.255;
    option routers 192.168.1.1;
    option ntp-servers 192.168.1.1;
    option domain-name-servers 192.168.1.1;
    allow unknown-clients;
  }

  subnet 192.168.2.0 netmask 255.255.255.0 {
    range 192.168.2.10 192.168.2.240;
    option subnet-mask 255.255.255.0;
    option broadcast-address 192.168.2.255;
    option routers 192.168.2.1;
    option ntp-servers 192.168.2.1;
    option domain-name-servers 192.168.1.1;
    ignore unknown-clients;
  }

  subnet 192.168.3.0 netmask 255.255.255.0 {
    range 192.168.3.10 192.168.3.240;
    option subnet-mask 255.255.255.0;
    option broadcast-address 192.168.3.255;
    option routers 192.168.3.1;
    option ntp-servers 192.168.3.1;
    option domain-name-servers 192.168.1.1;
    ignore unknown-clients;
  }
}

host Gaming_Computer {
  hardware ethernet 00:53:00:FF:FF:11;
  fixed-address 192.168.1.20;
  option subnet-mask 255.255.255.0;
  option broadcast-address 192.168.1.255;
  option routers 192.168.1.1;
  option host-name "gaming_computer";
}

host Linux_Workstation {
  hardware ethernet 00:53:00:FF:FF:22;
  fixed-address 192.168.2.21;
  option subnet-mask 255.255.255.0;
  option broadcast-address 192.168.2.255;
  option routers 192.168.2.1;
  option host-name "linux_workstation";
}

host printer {
  hardware ethernet 00:53:00:FF:FF:33;
  fixed-address 192.168.3.9;
  option subnet-mask 255.255.255.0;
  option broadcast-address 192.168.3.255;
  option routers 192.168.3.1;
}

配置完成后,请务必将其添加到默认运行级别

rc-update add dhcpd default

同步时钟

您可以选择使用 BusyBox 的 ntpd,也可以选择更成熟的选项,如 OpenNTPDChrony

Busybox /etc/conf.d/ntpd

允许客户端将其时钟与路由器同步。

# By default ntpd runs as a client. Add -l to run as a server on port 123.
NTPD_OPTS="-l -N -p <REMOTE TIME SERVER>"

配置完成后,请务必将其添加到默认运行级别

rc-update add ntpd default

或者,如果您愿意,可以与多个服务器同步...

Chrony /etc/chrony.conf

apk add chrony

logdir /var/log/chrony
log measurements statistics tracking

allow 192.168.0.0/30
allow 192.168.1.0/24
allow 192.168.2.0/24
allow 192.168.3.0/24
allow 192.168.4.0/24
broadcast 30 192.168.0.3
broadcast 30 192.168.1.255
broadcast 30 192.168.2.255
broadcast 30 192.168.3.255
broadcast 30 192.168.4.255

server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
server 3.pool.ntp.org iburst

initstepslew 10 pool.ntp.org
driftfile /var/lib/chrony/chrony.drift
hwclockfile /etc/adjtime
rtcdevice /dev/rtc0
rtcsync

OpenNTPD /etc/ntpd.conf

安装 OpenNTPD

apk add openntpd

添加到默认运行级别。

rc-update add openntpd default

/etc/ntpd.conf

# sample ntpd configuration file, see ntpd.conf(5)

# Addresses to listen on (ntpd does not listen by default)
listen on 192.168.1.1
listen on 192.168.2.1

# sync to a single server
#server pool.ntp.org

# use a random selection of NTP Pool Time Servers
# see https://support.ntp.org/Servers/NTPPoolServers
server 0.pool.ntp.org
server 1.pool.ntp.org
server 2.pool.ntp.org
server 3.pool.ntp.org

时区

您可能还想设置时区,请参阅 设置时区

保存时间

有两种方法可以做到这一点。如果您没有购买 RTC,请参阅 使用软件时钟保存时间。如果您购买了,例如 PiFace 实时时钟,请参阅 使用硬件时钟保存时间

带有 dnscrypt 的 Unbound DNS 转发器

我们希望能够使用 dnscrypt 进行查找,而无需在网络上的每个客户端上安装 DNSCrypt。DNSCrypt 可以使用其 自有协议DNS over HTTPS

路由器还将运行 DNS 转发器,并为我们的客户端通过 DNSCrypt 请求未知域名。借用自 ArchLinux wiki 上关于 dnscrypt-proxy 的文章。

Unbound

首先安装

apk add unbound

/etc/unbound/unbound.conf

server:
    # Use this to include other text into the file.
    include: "/etc/unbound/filter.conf"

    # verbosity number, 0 is least verbose. 1 is default.
    verbosity: 1

    # specify the interfaces to answer queries from by ip-address.
    # The default is to listen to localhost (127.0.0.1 and ::1).
    # specify 0.0.0.0 and ::0 to bind to all available interfaces.
    # specify every interface[@port] on a new 'interface:' labelled line.
    # The listen interfaces are not changed on reload, only on restart.
    interface: 192.168.2.1
    interface: 192.168.3.1

    # Enable IPv4, "yes" or "no".
    do-ip4: yes

    # Enable IPv6, "yes" or "no".
    do-ip6: yes

    # Enable UDP, "yes" or "no".
    do-udp: yes

    # Enable TCP, "yes" or "no".
    do-tcp: yes

    # control which clients are allowed to make (recursive) queries
    # to this server. Specify classless netblocks with /size and action.
    # By default everything is refused, except for localhost.
    # Choose deny (drop message), refuse (polite error reply),
    # allow (recursive ok), allow_setrd (recursive ok, rd bit is forced on),
    # allow_snoop (recursive and nonrecursive ok)
    # deny_non_local (drop queries unless can be answered from local-data)
    # refuse_non_local (like deny_non_local but polite error reply).
    # access-control: 0.0.0.0/0 refuse
    # access-control: 127.0.0.0/8 allow
    # access-control: ::0/0 refuse
    # access-control: ::1 allow
    # access-control: ::ffff:127.0.0.1 allow
    access-control: 192.168.1.0/24 allow
    access-control: 192.168.2.0/24 allow
    access-control: 192.168.3.0/24 allow

    # the log file, "" means log to stderr.
    # Use of this option sets use-syslog to "no".
    logfile: "/var/log/unbound/unbound.log"

    # Log to syslog(3) if yes. The log facility LOG_DAEMON is used to
    # log to. If yes, it overrides the logfile.
    use-syslog: no

    # print one line with time, IP, name, type, class for every query.
    # log-queries: no

    # print one line per reply, with time, IP, name, type, class, rcode,
    # timetoresolve, fromcache and responsesize.
    # log-replies: no

    # enable to not answer id.server and hostname.bind queries.
    hide-identity: yes

    # enable to not answer version.server and version.bind queries.
    # hide-version: yes

    # enable to not answer trustanchor.unbound queries.
    hide-trustanchor: yes


    # Harden against very small EDNS buffer sizes.
    harden-short-bufsize: yes

    # Harden against unseemly large queries.
    harden-large-queries: yes

    # Harden against out of zone rrsets, to avoid spoofing attempts.
    harden-glue: yes

    # Harden against receiving dnssec-stripped data. If you turn it
    # off, failing to validate dnskey data for a trustanchor will
    # trigger insecure mode for that zone (like without a trustanchor).
    # Default on, which insists on dnssec data for trust-anchored zones.
    harden-dnssec-stripped: yes

    # Harden against queries that fall under dnssec-signed nxdomain names.
    harden-below-nxdomain: yes

    # Harden the referral path by performing additional queries for
    # infrastructure data.  Validates the replies (if possible).
    # Default off, because the lookups burden the server.  Experimental
    # implementation of draft-wijngaards-dnsext-resolver-side-mitigation.
    # harden-referral-path: no

    # Harden against algorithm downgrade when multiple algorithms are
    # advertised in the DS record.  If no, allows the weakest algorithm
    # to validate the zone.
    harden-algo-downgrade: yes

    # Use 0x20-encoded random bits in the query to foil spoof attempts.
    # This feature is an experimental implementation of draft dns-0x20.
    use-caps-for-id: yes

    # Allow the domain (and its subdomains) to contain private addresses.
    # local-data statements are allowed to contain private addresses too.
    private-domain: "<HOSTNAME>"

    # if yes, the above default do-not-query-address entries are present.
    # if no, localhost can be queried (for testing and debugging).
    do-not-query-localhost: no

    # File with trusted keys, kept uptodate using RFC5011 probes,
    # initial file like trust-anchor-file, then it stores metadata.
    # Use several entries, one per domain name, to track multiple zones.
    #
    # If you want to perform DNSSEC validation, run unbound-anchor before
    # you start unbound (i.e. in the system boot scripts).  And enable:
    # Please note usage of unbound-anchor root anchor is at your own risk
    # and under the terms of our LICENSE (see that file in the source).
    # auto-trust-anchor-file: "@UNBOUND_ROOTKEY_FILE@"
    auto-trust-anchor-file: "/etc/unbound/root.key"

    # If unbound is running service for the local host, then it is useful
    # to perform lan-wide lookups to the upstream, and unblock the
    # long list of local-zones above.  If this unbound is a dns server
    # for a network of computers, disabled is better and stops information
    # leakage of local lan information.
    unblock-lan-zones: no

    # If you configure local-data without specifying local-zone, by
    # default, a transparent local-zone is created for the data.
    #
    # You can add locally served data with
    # local-zone: "local." static
    # local-data: "mycomputer.local. IN A 192.0.2.51"
    # local-data: 'mytext.local TXT "content of text record"'

    # request upstream over TLS (with plain DNS inside the TLS stream).
    # Default is no.  Can be turned on and off with unbound-control.
    # tls-upstream: no

    # Forward zones
    # Create entries like below, to make all queries for 'example.com' and
    # 'example.org' go to the given list of servers. These servers have to handle
    # recursion to other nameservers. List zero or more nameservers by hostname
    # or by ipaddress. Use an entry with name "." to forward all queries.
    # If you enable forward-first, it attempts without the forward if it fails.
    # forward-zone:
    #    name: "example.com"
    #    forward-addr: 192.0.2.68
    #    forward-addr: 192.0.2.73@5355  # forward to port 5355.
    #    forward-first: no
    #    forward-tls-upstream: no
    #    forward-no-cache: no
    # forward-zone:
    #    name: "example.org"
    #    forward-host: fwd.example.com

forward-zone:
    name: "."
    forward-addr: 172.16.32.1@53
    forward-addr: ::1@53000
    forward-addr: 127.0.0.1@53000

额外的 DNS 级别过滤

此脚本接收域名列表并生成过滤器文件。我们将所有查找定向到“0.0.0.1”,这是一个无效的 IP,应该立即失败,与 localhost 不同。

注意: 如果您要过滤来自基于 Windows 的 PC 的遥测数据,您应该使用 组策略ShutUp10

/etc/unbound/unbound.conf

在您的主 unbound 配置中,添加

include: /etc/unbound/filter.conf

用于准备/排序 Unbound 域名的脚本

#!/bin/sh

##################################################
# Script taken from 
# https://web.archive.org/web/20160815143410/http://npr.me.uk/unbound.html
# Note: you need GNU sed
##################################################

# Remove "#" comments
# Remove space and tab
# Remove blank lines
# Remove localhost and broadcasthost lines
# Keep just the hosts
# Remove leading and trailing space and tab (again)
# Make everything lower case

sed -e "s/#.*//" \
    -e "s/[ \x09]*$//"\
    -e "/^$/ d" \
    -e "/^.*local.*/ d" \
    -e "/^.*broadcasthost.*/ d" \
    -e "s/\(^.*\) \([a-zA-Z0-9\.\-]*\)/\2/" \
    -e "s/^[ \x09]*//;s/[ \x09]*$//" $1 \
    -e "s/\(.*\)/\L\1/" hosts.txt > temp1.txt

# Remove any duplicate hosts

sort temp1.txt | uniq >temp2.txt

# Remove any hosts starting with "."
# Create the two required lines for each host.

sed -e "/^\..*/ d" \
    -e "s/\(^.*\)/local-zone: \x22\1\x22 redirect\nlocal-data: \x22\1 A 0.0.0.1\x22/" \
       temp2.txt > filter.conf

# Clean up
rm temp1.txt
rm temp2.txt

DNSCrypt

您可以使用 dnsleak.comGRC 的这个网站来测试您是否没有 DNS 泄漏。诸如 CloudFlare 公共 DNSGoogle 公共 DNS 之类的提供商使用 任播,它应该指向位于您的 VPN 出口位置的服务器。

/etc/dnscrypt-proxy/dnscrypt-proxy.toml

使用示例 dnscrypt 配置即可。您需要进行以下更改

listen_addresses = ['127.0.0.1:53000', '[::1]:53000']

为 VPN 上的 dnscrypt 添加策略路由

根据 dnscrypt 用户的 uid 添加 基于策略的路由。在 Alpine Linux 上,dnscrypt-proxy 以特定用户身份运行,因此请检查 /etc/passwd

dnscrypt:x:103:104:dnscrypt:/var/empty:/sbin/nologin

在本例中,dnscrypt 用户的 uid 为 103。

警告: 确保检查 您的 dnscrypt 用户的 uid。不要只是复制这里的那个!


将其添加到 fwmark_rules,例如

/etc/network/fwmark_rules

# Route DNSCrypt user through the VPN table
/sbin/ip rule add uidrange 103-103 table VPN prio 200

rc-update add unbound default

rc-update add dnscrypt-proxy default

随机数生成

有两种方法可以协助随机数生成 熵和随机性。如果您要生成自己的 Diffie-Hellman nonce 文件(在 FreeRadius EAP-TLS 配置 部分中使用),或者任何诸如生成证书或公钥私钥之类的过程,这将特别有用。

Haveged

Haveged 是提高随机数生成速度的好方法。它使用基于 HAVEGE 算法改编的不可预测的随机数生成器。

安装 haveged

apk add haveged

启动 haveged 服务

service haveged start

将服务添加到启动项

rc-update add haveged default

启动 rngd 服务

service haveged start

将服务添加到启动项

rc-update add haveged default

带有 bcm2708-rng 的 rng-tools

Alpine Linux 3.8 之前版本(包含 rngd 5)

所有 Raspberry Pi 都板载 bcm2708-rng 随机数生成器。如果您在 Raspberry Pi 上进行此项目,那么您可以选择使用它。

将内核模块添加到 /etc/modules

echo "bcm2708-rng" > /etc/modules

插入模块

modprobe bcm2708-rng

安装 rng-tools

apk add rng-tools

在 /etc/conf.d/rngd 中设置随机设备 (/dev/random) 和 rng 设备 (/dev/hwrng)

RNGD_OPTS="--no-drng=1 --no-tpm=1 -o /dev/random -r /dev/hwrng"

Alpine Linux 3.8 之后版本(包含 rngd 6)

使用 AlpineLinux 3.8,您不必插入模块,因为它已内置在内核中。

此外,rngd 的语法已更改,因此对于 /etc/conf.d/rngd,您需要

RNGD_OPTS="-x1 -o /dev/random -r /dev/hwrng"

启动 rngd 服务

service rngd start

将服务添加到启动项

rc-update add rngd default

您可以使用以下命令进行测试

cat /dev/hwrng | rngtest -c 1000

您应该看到类似这样的内容

rngtest 5
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: bits received from input: 20000032
rngtest: FIPS 140-2 successes: 1000
rngtest: FIPS 140-2 failures: 0
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
rngtest: FIPS 140-2(2001-10-10) Poker: 0
rngtest: FIPS 140-2(2001-10-10) Runs: 0
rngtest: FIPS 140-2(2001-10-10) Long run: 0
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=117.709; avg=808.831; max=3255208.333)Kibits/s
rngtest: FIPS tests speed: (min=17.199; avg=22.207; max=22.653)Mibits/s
rngtest: Program run time: 25178079 microseconds

您可能会遇到一些故障。没关系,我之前做的两次运行每次都出现一次故障。

WiFi 802.1x EAP 和 FreeRadius

比使用预共享密钥 (WPA2) 更安全的方法是使用 EAP-TLS 并为每个设备使用单独的证书。请参阅 FreeRadius EAP-TLS 配置

特定子网上的 VPN 隧道

正如本文前面提到的,拥有 VPN 子网和非 VPN 子网可能很有用。通常,游戏机或计算机可能需要低延迟连接。对于本练习,我们使用 fwmark。

我们扩展网络以使其看起来像这样

Network Diagram with IPv4 tunnel
带有 IPv4 隧道的网络图

安装必要的软件包

apk add openvpn iproute2 iputils

/etc/modules

您需要添加 tun 模块

tun

/etc/iproute2/rt_tables

将两个路由表添加到 rt_tables 的底部。它应该看起来像这样

#
# reserved values
#
255	local
254	main
253	default
0	unspec
#
# local
#
#1	inr.ruhep
1 ISP
2 VPN

/etc/network/interfaces

接下来,添加虚拟接口(实际上只是 eth0 的 IP 地址)eth0:2,在 eth0 下面即可。

# Route to VPN subnet
auto eth0:2
iface eth0:2 inet static
  address 192.168.2.1
  netmask 255.255.255.0
  broadcast 192.168.2.255
  post-up /etc/network/fwmark_rules

/etc/sysctl.d/local.conf

如果您想使用 fwmark 规则,则需要更改此设置。它会导致路由器仍然进行源验证。

# Needed to use fwmark
net.ipv4.conf.all.rp_filter = 2

如果将此项设置为 1,则 fwmark 将不起作用。

/etc/network/fwmark_rules

在此文件中,我们要放置 fwmark 规则并设置正确的优先级。

#!/bin/sh

# Normal packets to go direct out WAN
/sbin/ip rule add fwmark 1 table ISP prio 100

# Put packets destined into VPN when VPN is up
/sbin/ip rule add fwmark 2 table VPN prio 200

# Prevent packets from being routed out when VPN is down.
# This prevents packets from falling back to the main table
# that has a priority of 32766
/sbin/ip rule add prohibit fwmark 2 prio 300

/etc/ppp/ip-up

接下来,我们要创建 PPP 联机时应运行的路由。在 ip-up 和 ip-down 中,我们可以使用特殊的钩子来引用 IP 地址,ppp man 文件 - Scripts 如果您安装了 ppp-doc,您也可以在您的 man 文件中阅读有关它们的信息。

#!/bin/sh
#
# This script is run by pppd when there's a successful ppp connection.
#

# Flush out any old rules that might be there
/sbin/ip route flush table ISP

# Add route to table from subnets on LAN
/sbin/ip route add 192.168.1.0/24 dev eth0 table ISP
/sbin/ip route add 192.168.2.0/24 dev eth0 table ISP

# Add route from IP given by ISP to the table
/sbin/ip rule add from ${IPREMOTE} table ISP prio 100

# Add a default route
/sbin/ip route add table ISP default via ${IPREMOTE} dev ${IFNAME}

/etc/ppp/ip-down

#!/bin/sh
#
# This script is run by pppd after the connection has ended.
#

# Delete the rules when we take the interface down
/sbin/ip rule del from ${IPREMOTE} table ISP prio 100

/etc/openvpn/route-up-fwmark.sh

OpenVPN 需要类似的路由脚本,并且它也有自己的特殊钩子,允许您指定特定值。完整列表在此处 OpenVPN man 文件 - 环境变量

#!/bin/sh
#
# This script is run by OpenVPN when there's a successful VPN connection.
#

# Flush out any old rules that might be there
/sbin/ip route flush table VPN

# Add route to table from 192.168.2.0/24 subnet on LAN
/sbin/ip route add 192.168.2.0/24 dev eth0 table VPN

# Add route from VPN interface IP to the VPN table
/sbin/ip rule add from ${ifconfig_local} table VPN prio 200

# Add a default route
/sbin/ip route add default via ${ifconfig_local} dev ${dev} table VPN

/etc/openvpn/route-pre-down-fwmark.sh

#!/bin/sh
#
# This script is run by OpenVPN after the connection has ended
#

# Delete the rules when we take the interface down
/sbin/ip rule del from ${ifconfig_local} table VPN prio 200

我发现,当启动和停止 OpenVPN 服务时,如果您使用

service openvpn stop

route-pre-down-fwmark.sh 中的规则未执行。

然而

rc-service openvpn stop

似乎可以正常工作。

允许路由到两个路由表的高级 IPtables 规则

这是先前规则集的扩展。它为 192.168.2.0 设置 NAT 伪装,以使用标记的数据包通过 VPN。

我使用这些指南完成了此操作

#########################################################################
# Advanced routing rule set
# Uses 192.168.1.0 via ISP
#      192.168.2.0 via VPN
#
# Packets to/from 192.168.1.0/24 are marked with 0x1 and routed to ISP
# Packets to/from 192.168.2.0/24 are marked with 0x2 and routed to VPN
#
#########################################################################

#
# NAT Table
# This is where translation of packets happens and "forwarding" of ports
# to specific hosts.
#
*nat

# Set default policies for table
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Port forwarding for Bittorrent
-A PREROUTING -i tun0 -p tcp -m tcp --dport 6881:6889 -j DNAT --to-destination 192.168.2.20
-A PREROUTING -i tun0 -p udp -m udp --dport 6881:6889 -j DNAT --to-destination 192.168.2.20

# Allows routing to our modem subnet so we can access the web interface
-A POSTROUTING -s 192.168.1.0/24 -d 192.168.0.1/32 -o eth1 -p tcp -m tcp --dport 80 -j MASQUERADE
-A POSTROUTING -s 192.168.2.0/24 -d 192.168.0.1/32 -o eth1 -p tcp -m tcp --dport 80 -j MASQUERADE

# Allows hosts of the network to use the VPN tunnel
-A POSTROUTING -o tun0 -j MASQUERADE

# Allows hosts of the network to use the PPP tunnel
-A POSTROUTING -o ppp0 -j MASQUERADE
COMMIT

#
# Filter Table
# This is where we decide to ACCEPT, DROP or REJECT things
#
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# Create rule chain per input interface for forwarding packets
:FWD_ETH0 - [0:0]
:FWD_ETH1 - [0:0]
:FWD_PPP0 - [0:0]
:FWD_TUN0 - [0:0]

# Create rule chain per input interface for input packets (for host itself)
:IN_ETH0 - [0:0]
:IN_ETH1 - [0:0]
:IN_PPP0 - [0:0]
:IN_TUN0 - [0:0]

# Create a log drop chain
:LOG_DROP - [0:0]

# Create a reject chain
:LOG_REJECT - [0:0]

# Pass input packet to corresponding rule chain
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth0 -j IN_ETH0
-A INPUT -i eth1 -j IN_ETH1
-A INPUT -i ppp0 -j IN_PPP0
-A INPUT -i tun0 -j IN_TUN0

# Track forwarded packets
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Pass forwarded packet to corresponding rule chain
-A FORWARD -i eth0 -j FWD_ETH0
-A FORWARD -i eth1 -j FWD_ETH1
-A FORWARD -i ppp0 -j FWD_PPP0
-A FORWARD -i tun0 -j FWD_TUN0

# Forward traffic to ISP
-A FWD_ETH0 -s 192.168.1.0/24 -j ACCEPT

# Forward traffic to VPN
-A FWD_ETH0 -s 192.168.2.0/24 -j ACCEPT

# Allow excepted server to be FORWARD to ppp0
#-A FWD_ETH0 -s 192.168.2.0/24 -d <IP_OF_EXCEPTED_SERVER>/32 -o ppp0 -j ACCEPT

# Forward SSH packets from network to modem
-A FWD_ETH1 -s 192.168.0.1/32 -d 192.168.1.0/24 -p tcp -m tcp --sport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A FWD_ETH1 -s 192.168.0.1/32 -d 192.168.2.0/24 -p tcp -m tcp --sport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Forward HTTP packets from network to modem
-A FWD_ETH1 -s 192.168.0.1/32 -d 192.168.1.0/24 -p tcp -m tcp --sport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A FWD_ETH1 -s 192.168.0.1/32 -d 192.168.2.0/24 -p tcp -m tcp --sport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Forward Bittorrent Port to workstation
-A FWD_TUN0 -d 192.168.2.20/32 -p tcp -m tcp --dport 6881:6889 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A FWD_TUN0 -d 192.168.2.20/32 -p udp -m udp --dport 6881:6889 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# SSH to Router
-A IN_ETH0 -s 192.168.1.0/24 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A IN_ETH0 -s 192.168.2.0/24 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# DNS to Router
-A IN_ETH0 -s 192.168.1.0/24 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
-A IN_ETH0 -s 192.168.2.0/24 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT

# FreeRadius Client (eg a UniFi AP)
-A IN_ETH0 -s 192.168.1.0/24 -p tcp -m tcp --dport 1812 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A IN_ETH0 -s 192.168.1.0/24 -p udp -m udp --dport 1812 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Ubiquiti UAP Device Discovery Broadcast
-A IN_ETH0 -s 192.168.1.0/24 -p udp -m udp --dport 10001 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# NTP to Router
-A IN_ETH0 -s 192.168.1.0/24 -p udp -m udp --dport 123 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A IN_ETH0 -s 192.168.2.0/24 -p udp -m udp --dport 123 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Accept traffic to router on both subnets
-A IN_ETH0 -s 192.168.1.0/24 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A IN_ETH0 -s 192.168.2.0/24 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Allow excepted server to be INPUT to eth0 from LAN
#-A IN_ETH0 -s 192.168.2.0/24 -d <IP_OF_EXCEPTED_SERVER>/32 -o ppp0 -j ACCEPT

# SSH To Modem from Router
-A IN_ETH1 -s 192.168.0.1/32 -d 192.168.0.0/30 -p tcp -m tcp --sport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# HTTP To Modem from Router
-A IN_ETH1 -s 192.168.0.1/32 -d 192.168.0.0/30 -p tcp -m tcp --sport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Accept incoming tracked PPP0 connection
-A IN_PPP0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Log dropped packets coming in on PPP0
-A IN_PPP0 -j LOG --log-prefix "DROP:INPUT " --log-level 6
-A IN_PPP0 -j LOG_DROP

# Accept incoming tracked TUN0 connection
-A IN_TUN0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Log dropped packets coming in on TUN0
-A IN_TUN0 -j LOG --log-prefix "DROP:INPUT " --log-level 6
-A IN_TUN0 -j LOG_DROP
COMMIT

#
# Mangle Table
# This is the place where our markings happen, whether they be 0x1 or 0x2
#
*mangle

# Set default policies for table
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Restore CONNMARK to the MARK (If one doesn't exist then no mark is set)
-A PREROUTING -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff

# If packet MARK is 2, then it means there is already a connection mark and the
# original packet came in on VPN
-A PREROUTING -s 192.168.2.0/24 -m mark --mark 0x2 -j ACCEPT

# Check exception (this is a server which when accessed on a 192.168.2.0/24 address will go out the ISP table) are 0x1
#-A PREROUTING -s 192.168.2.0/24 -d <IP_OF_EXCEPTED_SERVER>/32 -m mark --mark 0x1 -j ACCEPT

# Mark packets coming from 192.168.2.0/24 are 0x2
-A PREROUTING -s 192.168.2.0/24 -j MARK --set-xmark 0x2/0xffffffff

# If packet MARK is 1, then it means there is already a connection mark and the
# original packet came in on ISP
-A PREROUTING -s 192.168.1.0/24 -m mark --mark 0x1 -j ACCEPT

# Mark packets 192.168.1.0/24 are 0x1
-A PREROUTING -s 192.168.1.0/24 -j MARK --set-xmark 0x1/0xffffffff

# Mark exception (this is a server which when accessed on a 192.168.2.0/24 address will go out the ISP table) as 0x1
#-A PREROUTING -s 192.168.2.0/24 -d <IP_OF_EXCEPTED_SERVER>/32 -j MARK --set-xmark 0x1/0xffffffff

# Set mark to 0 - This is for the modem. Otherwise it will mark with 0x1 or 0x2
-A PREROUTING -d 192.168.0.1/32 -j MARK --set-xmark 0x0/0xffffffff

# Save MARK to CONNMARK (remember iproute can't see CONNMARKs)
-A PREROUTING -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff
COMMIT

您可能需要删除此处某些不适用于您的规则,例如 FreeRadius 规则。这将在本文后面介绍。

OpenVPN 路由

通常,当您连接到 OpenVPN 时,远程 VPN 服务器会将路由推送给您的系统。我们不希望这样做,因为我们仍然希望能够在不使用 VPN 的情况下访问互联网。我们还在本指南前面创建了我们想要使用的自己的路由。

您需要将其添加到您的 OpenVPN 配置文件底部

# Prevents default gateway from being set on the default routing table
route-noexec

# Allows route-up script to be executed
script-security 2

# Calls custom shell script after connection to add necessary routes
route-up /etc/openvpn/route-up-fwmark.sh
route-pre-down /etc/openvpn/route-pre-down-fwmark.sh

我的 VPN 在 /etc/openvpn 中这样排列

该服务器的 OpenVPN 配置文件

countrycode.serverNumber.openvpn.conf

该服务器的 OpenVPN 证书

countrycode.serverNumber.openvpn/countrycode.serverNumber.openvpn.crt
countrycode.serverNumber.openvpn/countrycode.serverNumber.openvpn.key
countrycode.serverNumber.openvpn/myKey.crt
countrycode.serverNumber.openvpn/myKey.key

所以我使用这个有用的脚本来自动化在服务器之间切换的过程

#!/bin/sh

vpn_server_filename=$1

rm /etc/openvpn/openvpn.conf
ln -s $vpn_server_filename /etc/openvpn/openvpn.conf
chown -R openvpn:openvpn /etc/openvpn
chmod -R a=-rwx,u=+rX /etc/openvpn
chmod u=x /etc/openvpn/*.sh*

if grep -Fxq "#CustomStuffHere" openvpn.conf
then
    echo "Not adding custom routes, this server has been used previously"
else
    echo "Adding custom route rules"
cat <<EOF >> /etc/openvpn/openvpn.conf

#CustomStuffHere
# Prevents default gateway from being set on the default routing table
route-noexec

# Allows route-up script to be executed
script-security 2

# Calls custom shell script after connection to add necessary routes
route-up /etc/openvpn/route-up-fwmark.sh
route-pre-down /etc/openvpn/route-pre-down-fwmark.sh

# Logging of OpenVPN to file
#log /etc/openvpn/openvpn.log
EOF

fi
echo "Remember to set BitTorrent port forward in VPN control panel"

这样,我只需运行以下命令即可在服务器之间切换

changevpn.sh countrycode.serverNumber.openvpn

然后重新启动 openvpn。我还被提醒在 VPN 控制面板上设置端口转发,以便我的 BitTorrent 客户端可以连接

service openvpn restart

最后,将 openvpn 添加到默认运行级别

rc-update add openvpn default

创建仅限 LAN 的子网

在本节中,我们将创建一个仅限 LAN 的子网。此子网将是 192.168.3.0/24。此子网的想法是其中的节点的数据包无法转发到 Internet,但是可以通过其他 LAN 子网 192.168.1.0/24 和 192.168.2.0/24 访问它们。此方法不使用 VLAN,尽管如果您有托管交换机,则建议使用 VLAN。此子网的想法是用于诸如 WiFi 接入点、联系本地 Asterisk 服务器的 IP 电话以及当然还有打印机之类的设备。

在本节末尾,我们将拥有类似这样的内容

Network Diagram LAN ONLY Route with IPv4
网络图 仅限 LAN 路由,带有 IPv4

/etc/iproute2/rt_tables

首先,我们将添加第三个路由表

3 LAN

/etc/network/interfaces

添加一个额外的虚拟接口(实际上只是 eth0 的 IP 地址)。

# LAN Only
auto eth0:3
iface eth0:3 inet static
  address 192.168.3.1
  netmask 255.255.255.0
  broadcast 192.168.3.255
  post-up /etc/network/route_LAN

/etc/network/route_LAN

此文件将添加我们的路由

#!/bin/sh

# Add routes from ISP to LAN
/sbin/ip route add 192.168.1.0/24 dev eth0 table LAN

# Add route from VPN to LAN
/sbin/ip route add 192.168.2.0/24 dev eth0 table LAN

# Add route from LAN to it's own table
/sbin/ip route add 192.168.3.0/24 dev eth0 table LAN

/etc/ppp/ip-up

将从 LAN 子网到 ISP 表的路由附加到

# Add route to LAN subnet
/sbin/ip route add 192.168.3.0/24 dev eth0 table ISP

/etc/openvpn/route-up-fwmark.sh

将从 LAN 子网到 VPN 表的路由附加到

# Add route to LAN only subnet
/sbin/ip route add 192.168.3.0/24 dev eth0 table VPN

/etc/ntpd.conf

为 ntp (OpenNTPD) 添加侦听地址。

您现在应该拥有

# Addresses to listen on (ntpd does not listen by default)
listen on 192.168.1.1
listen on 192.168.2.1
listen on 192.168.3.1

需要正确时间的设备将需要使用此 NTP 服务器,因为它们无法从 Internet 获取时间。

阻止非法地址

我们的 LAN 现在总共有 4 个可能的子网

  • 192.168.0.0/30(调制解调器和路由器之间的连接)
  • 192.168.1.0/24(ISP 表,直接路由出 WAN)
  • 192.168.2.0/24(VPN 表,路由出 VPN)
  • 192.168.3.0/24(仅限 LAN 主机的空路由子网)
  • 172.16.32.0/20(VPN 提供商的网络,因此我们可以访问 VPN 网络上的内容)。

其他所有内容都应被拒绝。永远不应在 192.168.5.2 或 10.0.0.5 等地址上转发数据包。

安装 ipset

安装 ipset

apk add ipset

将其添加到启动项

rc-update add ipset default

现在我们需要将地址列表加载到 ipset 中 使用 IPset 和动态阻止列表保护您的服务器 提到了一个 脚本,该脚本特别有用。如果您想定期更新它,并且对于完整的非法地址列表,您应该运行此脚本作为 cron 作业,因为当分配该地址空间时,它们会发生变化。

就此而言,我们将仅使用 bogon-bn-nonagg.txt 列表。

0.0.0.0/8
10.0.0.0/8
100.64.0.0/10
127.0.0.0/8
169.254.0.0/16
172.16.0.0/12
192.0.0.0/24
192.0.2.0/24
192.168.0.0/16
198.18.0.0/15
198.51.100.0/24
203.0.113.0/24
224.0.0.0/4
240.0.0.0/4

这不太可能改变,因为它是 IPV4 保留 IP 地址 空间。脚本

#! /bin/bash

# /usr/local/sbin/fullbogons-ipv4
# BoneKracker
# Rev. 11 October 2012
# Tested with ipset 6.13

# Purpose: Periodically update an ipset used in a running firewall to block
# bogons. Bogons are addresses that nobody should be using on the public
# Internet because they are either private, not to be assigned, or have
# not yet been assigned.
#
# Notes: Call this from crontab. Feed updated every 4 hours.

# target="https://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt"
# Use alternative URL from pfSense, due to 404 error with URL above
target="https://files.pfsense.org/lists/bogon-bn-nonagg.txt"
ipset_params="hash:net"

filename=$(basename ${target})
firewall_ipset=${filename%.*}           # ipset will be filename minus ext
data_dir="/var/tmp/${firewall_ipset}"   # data directory will be same
data_file="${data_dir}/${filename}"

# if data directory does not exist, create it
mkdir -pm 0750 ${data_dir}

# function to get modification time of the file in log-friendly format
get_timestamp() {
    date -r $1 +%m/%d' '%R
}

# file modification time on server is preserved during wget download
[ -w ${data_file} ] && old_timestamp=$(get_timestamp ${data_file})

# fetch file only if newer than the version we already have
wget -qNP ${data_dir} ${target}

if [ "$?" -ne "0" ]; then
    logger -p cron.err "IPSet: ${firewall_ipset} wget failed."
    exit 1
fi

timestamp=$(get_timestamp ${data_file})

# compare timestamps because wget returns success even if no newer file
if [ "${timestamp}" != "${old_timestamp}" ]; then

    temp_ipset="${firewall_ipset}_temp"
    ipset create ${temp_ipset} ${ipset_params}

    #sed -i '/^#/d' ${data_file}            # strip comments
    sed -ri '/^[#< \t]|^$/d' ${data_file}   # occasionally the file has been xhtml

    while read network; do
        ipset add ${temp_ipset} ${network}
    done < ${data_file}

    # if ipset does not exist, create it
    ipset create -exist ${firewall_ipset} ${ipset_params}

    # swap the temp ipset for the live one
    ipset swap ${temp_ipset} ${firewall_ipset}
    ipset destroy ${temp_ipset}

    # log the file modification time for use in minimizing lag in cron schedule
    logger -p cron.notice "IPSet: ${firewall_ipset} updated (as of: ${timestamp})."

fi

现在您应该在执行以下操作时看到列表已加载到内存中

ipset list

我们想要保存它,以便我们的路由器可以在下次启动时引用它。为此

rc-service ipset save

添加允许的网络

IPv4

ipset create allowed-nets-ipv4 hash:net,iface family inet

然后您可以添加每个允许的网络

ipset add allowed-nets-ipv4 192.168.0.0/30,eth1
ipset add allowed-nets-ipv4 192.168.1.0/24,eth0
ipset add allowed-nets-ipv4 192.168.2.0/24,eth0
ipset add allowed-nets-ipv4 192.168.3.0/24,eth0
ipset add allowed-nets-ipv4 127.0.0.0/8,lo
ipset add allowed-nets-ipv4 172.16.32.0/20,tun0

IPv6

对于 IPv6,如果您有任何 唯一本地地址 范围,您可以选择添加它们

ipset create allowed-nets-ipv6 hash:net,iface family inet6

ipset add allowed-nets-ipv6 fde4:8dba:82e1::/48,tun0
ipset add allowed-nets-ipv6 fde4:8dba:82e1:ffff::/64,eth0


最后,使用此命令保存集合,以便可以在下次启动时加载它们

rc-service ipset save

使用 iptables 限制 LAN 子网并阻止非法地址

最后,我们可以应用我们的 iptables 规则,来过滤 192.168.3.0/24 网段,并确保像 192.168.5.0/24 这样的子网不会被我们的路由器转发或访问。 您需要检查这些规则,并删除不适用于您的规则。

如果您已将 WiFi AP 移动到 192.168.3.0/24 子网,请不要忘记更改您的 RADIUS 规则。 您还需要编辑 /etc/raddb/clients.conf 文件。

我在这里使用了一个名为 “raw” 的新表。 此表比 filter 表更底层。 它不能有 FORWARD 规则或 INPUT 规则。 因此,您仍然需要在您的 filter 表中设置一个 FORWARD 规则来阻止来自 LAN 的非法网络流量(bogons)。

我们在这里唯一可以使用的规则类型是 PREROUTING 和 OUTPUT。 OUTPUT 规则将仅过滤来自我们路由器本地进程的流量,例如,如果我们从路由器的命令提示符对非法网络流量范围执行 ping 命令。

流量在连接标记之前会经过 raw 表,如这个数据包流向图所示: Netfilter 数据包流向图 这意味着我们不再需要在 mangle 表中剥离非法网络流量范围的标记。

#########################################################################
# Advanced routing rule set
# Uses 192.168.1.0 via ISP
#      192.168.2.0 via VPN
#      192.168.3.0 via LAN
#
# Packets to/from 192.168.1.0/24 are marked with 0x1 and routed to ISP
# Packets to/from 192.168.2.0/24 are marked with 0x2 and routed to VPN
# Packets to/from 192.168.3.0/24 are routed to LAN and not forwarded onto
#                                    the internet
#
#########################################################################

#
# Raw Table
# This table is the place where we drop all illegal packets from networks that
# do not exist
#
*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

# Create a log drop chain
:LOG_DROP_BOGON - [0:0]

# Create an output chain
:OUT_PPP0 - [0:0]
:OUT_TUN0 - [0:0]

# Allows traffic from VPN tunnel
-A PREROUTING -s 172.16.32.0/20 -i tun0 -j ACCEPT

# Allows traffic to VPN tunnel
-A PREROUTING -d 172.16.32.0/20 -j ACCEPT

# Block specified bogons coming in from ISP and VPN
# (unlikely to happen as they filter them on their router)
-A PREROUTING -i ppp0 -m set --match-set bogon-bn-nonagg src -j LOG_DROP_BOGON
-A PREROUTING -i tun0 -m set --match-set bogon-bn-nonagg src -j LOG_DROP_BOGON

# Allows my excepted ranges.
-A PREROUTING -m set --match-set allowed-nets-ipv4 src,src -j ACCEPT

# Pass output interface to corresponding chain
-A OUTPUT -o ppp0 -j OUT_PPP0
-A OUTPUT -o tun0 -j OUT_TUN0

# Log drop chain
-A LOG_DROP_BOGON -j LOG --log-prefix "Dropped Bogon (ipv4) : " --log-level 6
-A LOG_DROP_BOGON -j DROP

# Block packets originating from the router destined to bogon ranges
-A OUT_PPP0 -m set --match-set bogon-bn-nonagg dst -j LOG_DROP_BOGON

# Blocks packets originating from the router destined to bogon ranges
-A OUT_TUN0 -d 172.16.32.0/20 -j ACCEPT
-A OUT_TUN0 -m set --match-set bogon-bn-nonagg dst -j LOG_DROP_BOGON
COMMIT

#
# NAT Table
# This is where translation of packets happens as well as "forwarding" of ports
# to specific hosts.
#
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Port forwarding for Bittorrent
-A PREROUTING -i tun0 -p tcp -m tcp --dport 6881:6889 -j DNAT --to-destination 192.168.2.20
-A PREROUTING -i tun0 -p udp -m udp --dport 6881:6889 -j DNAT --to-destination 192.168.2.20

# Allows routing to our modem subnet so we can access the web interface
-A POSTROUTING -s 192.168.1.0/24 -d 192.168.0.1/32 -o eth1 -p tcp -m tcp --dport 80 -j MASQUERADE
-A POSTROUTING -s 192.168.2.0/24 -d 192.168.0.1/32 -o eth1 -p tcp -m tcp --dport 80 -j MASQUERADE

# Allows hosts of the network to use the VPN tunnel
-A POSTROUTING -o tun0 -j MASQUERADE

# Allows hosts of the network to use the PPP tunnel
-A POSTROUTING -o ppp0 -j MASQUERADE
COMMIT

#
# Filter Table
# This is where we decide to ACCEPT, DROP or REJECT packets
#
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# Create rule chain per input interface for forwarding packets
:FWD_ETH0 - [0:0]
:FWD_ETH1 - [0:0]
:FWD_PPP0 - [0:0]
:FWD_TUN0 - [0:0]

# Create rule chain per input interface for input packets (for host itself)
:IN_ETH0 - [0:0]
:IN_ETH1 - [0:0]
:IN_PPP0 - [0:0]
:IN_TUN0 - [0:0]

# Create a drop chain
:LOG_DROP - [0:0]

# Create a log drop chain
:LOG_DROP_BOGON - [0:0]

# Create a reject chain
:LOG_REJECT_LANONLY - [0:0]

# Create an output chain
:OUT_PPP0 - [0:0]
:OUT_TUN0 - [0:0]

# Pass input packet to corresponding rule chain
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth0 -j IN_ETH0
-A INPUT -i eth1 -j IN_ETH1
-A INPUT -i ppp0 -j IN_PPP0
-A INPUT -i tun0 -j IN_TUN0

# Track forwarded packets
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Pass forwarded packet to corresponding rule chain
-A FORWARD -i eth0 -j FWD_ETH0
-A FORWARD -i eth1 -j FWD_ETH1
-A FORWARD -i ppp0 -j FWD_PPP0
-A FORWARD -i tun0 -j FWD_TUN0

# Pass output interface to corresponding chain
-A OUTPUT -o ppp0 -j OUT_PPP0
-A OUTPUT -o tun0 -j OUT_TUN0

# Forward traffic to Modem
-A FWD_ETH0 -d 192.168.0.1/32 -j ACCEPT

# Allow routing to remote address on VPN
-A FWD_ETH0 -s 192.168.1.0/24 -d 172.16.32.1/32 -o tun0 -j ACCEPT
-A FWD_ETH0 -s 192.168.2.0/24 -d 172.16.32.1/32 -o tun0 -j ACCEPT

# Allow forwarding from LAN hosts to LAN ONLY subnet
-A FWD_ETH0 -s 192.168.1.0/24 -d 192.168.3.0/24 -j ACCEPT
-A FWD_ETH0 -s 192.168.2.0/24 -d 192.168.3.0/24 -j ACCEPT

# Allow LAN ONLY subnet to contact other LAN hosts
-A FWD_ETH0 -s 192.168.3.0/24 -d 192.168.1.0/24 -j ACCEPT
-A FWD_ETH0 -s 192.168.3.0/24 -d 192.168.2.0/24 -j ACCEPT

# Refuse to forward bogons to the internet!
-A FWD_ETH0 -m set --match-set bogon-bn-nonagg dst -j LOG_DROP_BOGON

# Forward traffic to ISP
-A FWD_ETH0 -s 192.168.1.0/24 -j ACCEPT

# Forward traffic to VPN
-A FWD_ETH0 -s 192.168.2.0/24 -j ACCEPT

# Prevent 192.168.3.0/24 from accessing internet
-A FWD_ETH0 -s 192.168.3.0/24 -j LOG_REJECT_LANONLY

# Allow excepted server to be FORWARD to ppp0
#-A FWD_ETH0 -s 192.168.2.0/24 -d <IP_OF_EXCEPTED_SERVER>/32 -o ppp0 -j ACCEPT

# Forward SSH packets from network to modem
-A FWD_ETH1 -s 192.168.0.1/32 -d 192.168.1.0/24 -p tcp -m tcp --sport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A FWD_ETH1 -s 192.168.0.1/32 -d 192.168.2.0/24 -p tcp -m tcp --sport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Forward HTTP packets from network to mode
-A FWD_ETH1 -s 192.168.0.1/32 -d 192.168.1.0/24 -p tcp -m tcp --sport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A FWD_ETH1 -s 192.168.0.1/32 -d 192.168.2.0/24 -p tcp -m tcp --sport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Forward Bittorrent Port to workstation
-A FWD_TUN0 -d 192.168.2.20/32 -p tcp -m tcp --dport 6881:6889 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A FWD_TUN0 -d 192.168.2.20/32 -p udp -m udp --dport 6881:6889 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# SSH to Router
-A IN_ETH0 -s 192.168.1.0/24 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A IN_ETH0 -s 192.168.2.0/24 -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# DNS to Router
-A IN_ETH0 -s 192.168.1.0/24 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
-A IN_ETH0 -s 192.168.2.0/24 -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT

# FreeRadius Client (eg a UniFi AP)
-A IN_ETH0 -s 192.168.3.10/32 -p tcp -m tcp --dport 1812 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A IN_ETH0 -s 192.168.3.10/32 -p udp -m udp --dport 1812 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Ubiquiti UAP Device Discovery Broadcast
-A IN_ETH0 -s 192.168.3.10/32 -p udp -m udp --dport 10001 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# NTP to Router
-A IN_ETH0 -s 192.168.1.0/24 -p udp -m udp --dport 123 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A IN_ETH0 -s 192.168.2.0/24 -p udp -m udp --dport 123 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A IN_ETH0 -s 192.168.3.0/24 -p udp -m udp --dport 123 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Accept traffic to router on both subnets
-A IN_ETH0 -s 192.168.1.0/24 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A IN_ETH0 -s 192.168.2.0/24 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Allow excepted server to be INPUT to eth0 from LAN
#-A IN_ETH0 -s 192.168.2.0/24 -d <IP_OF_EXCEPTED_SERVER>/32 -o ppp0 -j ACCEPT

# SSH To Modem from Router
-A IN_ETH1 -s 192.168.0.1/32 -d 192.168.0.0/30 -p tcp -m tcp --sport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# HTTP To Modem from Router
-A IN_ETH1 -s 192.168.0.1/32 -d 192.168.0.0/30 -p tcp -m tcp --sport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

# Accept incoming tracked PPP0 connection
-A IN_PPP0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Log dropped packets coming in on PPP0
-A IN_PPP0 -j LOG --log-prefix "DROP:INPUT (ipv4) " --log-level 6
-A IN_PPP0 -j LOG_DROP

# Accept incoming tracked TUN0 connection
-A IN_TUN0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Log dropped packets coming in on TUN0
-A IN_TUN0 -j LOG --log-prefix "DROP:INPUT (ipv4) " --log-level 6
-A IN_TUN0 -j LOG_DROP

# Log dropped bogons that never got forwarded
-A LOG_DROP_BOGON -j LOG --log-prefix "Dropped Bogon forward (ipv4) " --log-level 6
-A LOG_DROP_BOGON -j DROP

# Log rejected packets
-A LOG_REJECT_LANONLY -j LOG --log-prefix "Rejected packet from LAN only range : " --log-level 6
-A LOG_REJECT_LANONLY -j REJECT --reject-with icmp-port-unreachable
COMMIT

#
# Mangle Table
# This is the place where our markings happen, whether they be 0x1 or 0x2
#
*mangle

# Set default policies for table
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Restore CONNMARK to the MARK (If one doesn't exist then no mark is set)
-A PREROUTING -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff

# If packet MARK is 2, then it means there is already a connection mark and the
# original packet came in on VPN
-A PREROUTING -s 192.168.2.0/24 -m mark --mark 0x2 -j ACCEPT

# Check exception (this is a server which when accessed on a 192.168.2.0/24 address will go out the ISP table) are 0x1
#-A PREROUTING -s 192.168.2.0/24 -d <IP_OF_EXCEPTED_SERVER>/32 -m mark --mark 0x1 -j ACCEPT

# Mark packets coming from 192.168.2.0/24 are 0x2
-A PREROUTING -s 192.168.2.0/24 -j MARK --set-xmark 0x2/0xffffffff

# If packet MARK is 1, then it means there is already a connection mark and the
# original packet came in on ISP
-A PREROUTING -s 192.168.1.0/24 -m mark --mark 0x1 -j ACCEPT

# Mark packets 192.168.1.0/24 are 0x1
-A PREROUTING -s 192.168.1.0/24 -j MARK --set-xmark 0x1/0xffffffff

# Mark exception (this is a server which when accessed on a 192.168.2.0/24 address will go out the ISP table) as 0x1
#-A PREROUTING -s 192.168.2.0/24 -d <IP_OF_EXCEPTED_SERVER>/32 -j MARK --set-xmark 0x1/0xffffff

# Strip mark if packet is destined for modem
-A PREROUTING -d 192.168.0.1/32 -j MARK --set-xmark 0x0/0xffffffff

# Save MARK to CONNMARK (remember iproute can't see CONNMARKs)
-A PREROUTING -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff
COMMIT

其他提示

诊断防火墙问题

netcat, netcat6

Netcat 可用于测试端口是打开、关闭还是被过滤。

apk add netcat-openbsd

安装 netcat 后,我们可以像这样使用它

假设我们想要测试 IPv6、UDP、端口 547,我们将在路由器上执行以下操作

nc -6 -u -l 547

然后在客户端上执行以下操作以连接到它

nc -u -v -6 2001:0db8:1234:0001::1 547

tcpdump

tcpdump 也可用于转储接口上接收的数据包内容

apk add tcpdump

然后我们可以运行它。 此示例捕获所有来自 192.168.2.20 的 DNS 流量。

tcpdump -i eth0 udp and src 192.168.2.20 and port 53

您可以使用 -w 选项将文件输出,并在您本地计算机上的 Wireshark 中查看它。 您可以使用 -v 选项增加详细程度。 使用 -vv 将会更加详细。 -vvv 将显示更多信息。

lbu cache

配置 lbu cache,以便在重启路由器时不需要下载软件包,例如 本地 APK 缓存

这一点尤其重要,因为某些镜像不包含 ppp-pppoe。 这可能意味着您在启动时无法获得互联网连接来下载其他软件包。

lbu encryption /etc/lbu/lbu.conf

在 /etc/lbu/lbu.conf 中,您可能需要启用加密来保护您的 VPN 密钥。

# what cipher to use with -e option
DEFAULT_CIPHER=aes-256-cbc

# Uncomment the row below to encrypt config by default
ENCRYPTION=$DEFAULT_CIPHER

# Uncomment below to avoid <media> option to 'lbu commit'
# Can also be set to 'floppy'
LBU_MEDIA=mmcblk0p1

# Set the LBU_BACKUPDIR variable in case you prefer to save the apkovls
# in a normal directory instead of mounting an external medium.
# LBU_BACKUPDIR=/root/config-backups

# Uncomment below to let lbu make up to 3 backups
# BACKUP_LIMIT=3

请记住设置 root 密码,默认情况下 Alpine Linux 的 root 帐户是无密码的。

passwd root

备份 apkprov

备份您的 apk provision 文件是个好主意。 您可以使用以下命令将其从路由器拉取到您的本地工作站

scp -r root@192.168.2.1:/media/mmcblk0p1/<YOUR HOST NAME>.apkovl.tar.gz.aes-256-cbc ./

并使用以下命令解密它

openssl enc -d -aes-256-cbc -in <YOUR HOST NAME>.apkovl.tar.gz.aes-256-cbc -out <YOUR HOST NAME>.apkovl.tar.gz

可以使用以下命令加密它

openssl aes-256-cbc -salt -in <YOUR HOST NAME>.apkovl.tar.gz -out <YOUR HOST NAME>.apkovl.tar.gz.aes-256-cbc

加固 SSH

生成 SSH 密钥

ssh-keygen -t rsa -b 4096

您需要将 id_rsa.pub 的内容放入 /etc/ssh/authorized_keys 中

如果有多人可以访问路由器,您可以将多个公钥放在多行上。

/etc/ssh/sshd_config

以下是一些可以在此处设置的不错选项

ListenAddress 192.168.1.1
ListenAddress 192.168.2.1

虽然这通常不是一个好主意,但路由器不需要超过一个用户。

PermitRootLogin yes

最重要的选项

RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile  /etc/ssh/authorized_keys
PasswordAuthentication no
PermitEmptyPasswords no
AllowTcpForwarding no
X11Forwarding no

/etc/conf.d/sshd

您需要添加

rc_need="net"

这指示 OpenRC 确保在启动 SSH 之前网络已启动。

最后将 sshd 添加到默认运行级别

rc-update add sshd default


此外,您可能需要查看 Secure Secure Shell 并加强 OpenSSH 的加密选项。

参考