debian搭建简易路由笔记(未完成外网部分)
debian 简易路由(网关计算机)笔记
目标,利用已有的软件包,多网卡配置一个路由器
还没完成的配置学习:
- 流量控制
- 多个wan口配置
- PPPOE拨号
事实上我在github看到一个关于pppoe集成到systemd的讨论,抄作业即可
路由能力
-
动态地址转换NAT
-
LAN口可以DHCP动态分配IP地址,代理DNS服务。
-
防火墙,禁止主动从外网访问本机端口。
-
可以设置端口映射
硬件
-
主机一台
-
网卡2口,一口做wan,一口做lan
涉及软件包
系统:debian10
防火墙:nftables(代替iptables)
DHCP/DNS服务:dnsmasq
网卡接口管理服务:systemd-udevd systemd-networkd
流量控制和策略路由:iproute2 (这个还没开始学习)
配置思路
-
(1)使用systemd-udevd服务对网卡名更改,方便修改
nftables规则 -
(2)使用networkctl配合system-networkd管理网卡
-
(3)使用nftables配置nat规则以及防火墙规则
-
(4)使用dnsmasq绑定lan口网卡,启用DHCP服务、DNS服务
安装软件包
sudo apt install nftables dnsmasq iproute2
新建systemd.link规则修改网卡名
步骤流程:
-
(1) 卸载掉现在的网络管理(主要针对
networking和NetworkManager) -
(2) 修改udev规则,达到修改网卡名的目的(防火墙规则需要判断网卡名)
-
(3) 编写防火墙规则,使得内网流量出去时会被做SNAT。
-
(4) 创建DHCP服务、DNS服务,为局域网下的主机分配动态分配IP。
1.通过ip addr 查询 网卡MAC地址
例如
#ip addr
2: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 23:33:33:33:33:04 brd ff:ff:ff:ff:ff:ff
3: enp5s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 23:33:33:33:33:05 brd ff:ff:ff:ff:ff:ff
inet 192.168.31.33/24 brd 192.168.31.255 scope global dynamic
link/ehter项目对应的是mac地址,记住他们
-
wan网络接口:
23:33:33:33:33:04 -
lan网络接口:
23:33:33:33:33:05
后续有用到这两个MAC地址的配置根据实际情况替换。
2.通过mac地址匹配udev规则来修改网卡名
这一小节需要参考的文档有systemd.link 中文手册,利用mac地址匹配网卡设备,更改网卡名。
使用systemd.link为wan、lan网口创建网络接口名称命名规则的配置,创建配置文件:
sudo touch /lib/systemd/network/01-wan.link
sudo touch /lib/systemd/network/01-lan.link
文件内容如下,主要通过MAC地址进行匹配,参数含义参考手册,link配置由systemd-udevd读取。
#/lib/systemd/network/01-wan.link
[Match]
MACAddress=23:33:33:33:33:04
[Link]
Description=wan interface
Name=wan
AutoNegotiation=yes
TCPSegmentationOffload=yes
TCP6SegmentationOffload=yes
GenericReceiveOffload=yes
LargeReceiveOffload=yes
#/lib/systemd/network/01-lan.link
[Match]
MACAddress=23:33:33:33:33:05
[Link]
Description=lan interface
Name=lan # 新的接口名称
AutoNegotiation=yes
TCPSegmentationOffload=yes
TCP6SegmentationOffload=yes
GenericReceiveOffload=yes
LargeReceiveOffload=yes
切换systemd-networkd接管网卡,卸载networking和NetWorkManager服务
-
使用
ifupdown包做网络管理,对应的服务为networking.service -
使用
network-manager对应的则是NetworkManager.service
网络管理软件可能通过两个源头来触发网络配置:服务与udev规则;如果禁用服务失败,需要考虑是否因为udev的rule触发事件导致配置变化。
1.卸载其他网络管理
sudo apt purge ifupdown network-manager
网络管理服务一般情况只存在一个,此处使用systemd-networkd作为网络管理服务,它包括:
-
systemd-resolved.service(DNS服务)
-
systemd-networkd.service(网络管理服务)
-
systemd-networkd-wait-online.service(等待网络在线服务,用于阻塞)
三个相关服务,对应的命令有networkctl、resolvectl。
2.编写systemd.network配置文件
创建 10-wan.network、10-lan.network 两个配置,文件名没要求,后缀要求是.network
sudo touch /etc/systemd/network/10-wan.network
sudo touch /etc/systemd/network/10-lan.network
3.编辑规则
注:wan口暂时没有学习配置PPPOE拨号,还得继续学习。
wan口暂时设置为DHCP方式上网
wan口网络配置文件内容如下:
#/etc/systemd/network/10-wan.network
[Match]
MACAddress=23:33:33:33:33:04
[Link]
RequiredForOnline=no
[Network]
Description=wan network
DHCP=yes
IPForward=yes
NTP=ntp.aliyun.com
lan口网络配置文件内容如下:
# /etc/systemd/network/lan.network
# lan口静态ip 192.168.31.1
[Match]
MACAddress=23:33:33:33:33:05
[Link]
RequiredForOnline=no
[Network]
Description=LAN network
Address=192.168.31.1/24
IPForward=yes
4.启用systemd-networkd服务,允许开机自启
sudo systemctl daemon-reload
sudo systemctl enable systemd-networkd
sudo systemctl start systemd-networkd
5.使用systemd-resolved.service管理主机DNS,配置关闭监听53端口及5355端口
使用systemd-networkd管理网络,还需要启用systemd-resolved管理本机的DNS服务,确保域名解正常。
编辑systemd-resolved.service 配置文件如下:
# /etc/systemd/resolved.conf
[Resolve]
DNS=223.5.5.5 223.6.6.6
Cache=yes
DNSStubListener=no
ReadEtcHosts=yes
LLMNR=no
选项配置如下:
-
(1) DNS: 空格分隔的上级DNS服务器,这里使用阿里云dns
-
(2) Cache:设置缓存解释成功的域名
-
(3) DNSStubListener:禁用本地DNS服务器,这个选项设置为no避免监听127.0.0.1:53
-
(4) ReadEtcHosts:设置为yes,发送查询请求前,会优先查询/etc/hosts
-
(5) LLMNR:设置为no,它将不会监听5355端口。
启动并允许开机启动:
sudo systemctl enable systemd-resolved.service
sudo systemctl start systemd-resolved.service
sysctl调整参数
对于内核网络调整方面接触较少,本节网上抄作业,但是调整参数选项的含义需要参考linux内核网络文档。
主要的调整目标为:
-
允许流量转发
-
不允许外网ping内网的IP地址
添加以下配置:
# /etc/sysctl.conf
net.ipv4.tcp_syncookies=1
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.default.arp_ignore = 1
net.ipv4.conf.default.rp_filter = 1
调整说明:
-
accept_source_route = 0 不接受路由报头。
-
arp_announce = 2 定义接口上发送的ARP请求中的IP报文宣布本端源IP地址的不同限制级别,当值为2时,总是为这个目标使用最佳的本地地址。在这种模式下,忽略IP包中的源地址,并尝试选择我们喜欢的本地地址与目标主机进行对话。通过在包含目标IP地址的出接口的所有子网中查找主IP地址来选择这种本地地址。如果没有找到合适的本地地址,我们就选择出接口或所有其他接口上的第一个本地地址,希望能够收到对我们请求的回应,甚至有时不管我们宣布的源IP地址是什么。
-
arp_ignore = 1 对于收到的解析本端目标IP地址的ARP请求,定义不同的应答方式,值为1时,只有当目标IP地址为入接口上配置的本端地址时才进行应答。
-
rp_filter = 1 严格模式RFC3704中定义的严格反向路径对每个入方向的报文进行FIB测试,如果接口不是最佳反向路径则报文检查失败。缺省情况下,失败的报文将被丢弃。
编写防火墙规则
1.编辑/etc/nftables.conf,写入具体规则
-
默认外网从wan口进来的流量访问的端口是被过滤的。
-
允许从内网主动发起的链接通过。
-
允许局域网内访问网关计算机。
-
网关计算机允许被ping。
-
从lan口流入内核,又没从lan口流出的流量,并且源ip符合ip段的流量,在postrouting钩子下的链要做masquerade规则,做特殊的SNAT,在本路由器处,做源地址转换,替换成
wan口的网络地址,当数据包返回的时候,将目的地址替换成远程访问的IP。
此处的规则有个坑,因为
input钩子下的规则,默认的行为是把阻止链接,如果网关计算机要监听某个端口,需要在/etc/nftables.conf里添加放行规则。
/etc/nftables.conf 文件内容(comment关键字可以为规则添加注释,增强可读性)
flush ruleset
# IPv4协议簇的表,用于储存nat相关的规则,此处只用到prerouting和postrouting的钩子
# 这里有个问题,如果{后的空行,因为对齐的原因被补全了个tab,可能出现语法错误,如果单独空行,不应该用任何的空白符号占用它,但是可以用回车换行,单行即无注释又无定义语句,且有空白字符占用空行,可能出现多余的字符造成错误
table ip nat {
chain PREROUTING {
type nat hook prerouting priority 100; policy accept
#如果需要端口转发,则在PREROUTING钩子的链做DNAT
iif wan tcp dport 65533 dnat to 192.168.31.2:22 comment "dnat: :65533 => 192.168.31.2:22"
# 把wan口进来的流量,目标端口是65533的发往192.168.31.2的22端口
}
chain POSTROUTING {
type nat hook postrouting priority 100; policy accept;
#做动态SNAT (备注②)
meta iif lan oif != lan ip saddr 192.168.31.0/24 masquerade comment "lan口流量外网NAT规则"
}
}
# IPv4防火墙规律规则,主要针对进本机的流量
table ip filter {
chain INPUT {
#默认的策略是不允许流量通过
type filter hook input priority 0; policy drop;
iif {lo,lan} accept comment "允许lo口、lan口流进的内网流量通过"
icmp type echo-request counter accept comment "允许被ping"
#备注①
ct state established,related accept comment "允许从内部主动发起的链接通过"
}
}
# IPv6防火墙规律规则,主要针对进本机的流量
table ip6 filter {
chain INPUT {
type filter hook input priority 0; policy drop
ct state established,related accept comment "允许从内部主动发起的链接通过"
iif {lo, lan} accept comment "允许lo口、lan口流进的内网流量通过"
icmpv6 type {echo-request,nd-neighbor-solicit} accept comment "允许被ping"
}
}
备注①:ct state established,related accept; 这条规则匹配链接状态的,链接状态和iptables的保持一致,有4种状态,ESTABLISHED、NEW、RELATED及INVALID,链接过程,客户端发出请求,服务端返回结果,刚好源地址/目的地址是相反的,第一个穿越防火墙的数据包,链接状态是NEW,后续的数据包(无论是请求还是应答)链接状态是ESTABLISHED,有一种情况,类似于FTP,区分数据端口和控制端口的,被动产生的数据包,第一个,但是不属于任何链接中的,它的状态是RELATED,而这个链接产生后,这条链路后续的数据包状态都是ESTABLISHED,最后一种是三种状态之外的数据包。
具体的情况分析:
-
(1) 由本地作为客户端,主动去访问服务端(就好像我们访问网站的情况),此时我们的请求,发送出去,我们第一个数据包是NEW状态,netfilter追踪这个链接的状态。
-
(2) 请求发出后,这条链路下一个返回的数据包,已经是ESTABLISHED状态了,但是如果此时防火墙,没有允许相关状态的链接通过,默认策略是drop的,会导致我们的包可以发出去,但是回来时被input默认DROP规则过滤。
-
(3) 允许ESTABLISHED状态的数据包通过,可以让本机主动发出的请求后,回来的数据包,可以通过防火墙。
备注②:masquerade 是一种特殊的SNAT,按nftables的wiki说明,它只有在postrouting的钩子下才有意义的,此时,已经选中了路由,准备要发往对应的网卡了,masquerade会把源ip替换成该网卡对应的ip,然后记录这条信息,当数据返回的时候(prerouting),它会查找记录,又会把masquerade前的源ip替换成目的的IP(DNAT),这样,相当于“隐藏”了网关计算机自身,把链路转发到masquerade前的源ip主机。
DNS/DHCP服务配置
使用dnsmasq守护进程作为网关计算机的DNS以及DHCP服务。
/etc/systemd/resolved.conf的默认设置会占用了53端口和5355端口,需要额外设置,详情看前面。
1.安装
sudo apt install dnsmasq
2.配置
把 dnsmasq默认的配置都不要了,把sysV启动的软连接全部删了,把 dnsmasq.service 的服务也删除了。可以满足多个网卡配置dnsmasq,不应该使用包内自带的服务配置,由自己编辑一个适合情况的配置文件。
#删除sysV init 开机自启的软连接
find /etc/rc[0-9S].d -name "*dnsmasq*" -exec sudo rm {} \;
#删除dnsmasq默认包的服务配置
sudo rm sudo rm /lib/systemd/system/dnsmasq.service
#重载配置
sudo systemctl daemon-reload
编写新的dnsmasq服务的service模板,以适应多个网卡单独启动不同的dnsmasq服务。
sudo touch /etc/systemd/system/dnsmasq@.service
编写 /etc/systemd/system/dnsmasq@.service 内容:
# /etc/systemd/system/dnsmasq@.service
[Unit]
Description=IPv4 DHCP server on %I
Wants=network.target
After=network.target
[Service]
Type=forking
PIDFile=/run/dnsmasq@%I.pid
ExecStart=/usr/sbin/dnsmasq --except-interface=lo --pid-file=/run/dnsmasq@%I.pid --log-facility=/var/log/dnsmasq/%I.log --interface=%I --conf-file=/opt/router-config/dnsmasq/%I/dnsmasq.conf --dhcp-leasefile=/opt/router-config/dnsmasq/%I/dnsmasq.leases --dhcp-hostsfile=/opt/router-config/dnsmasq/%I/hosts.d/ --resolv-file=/opt/router-config/dnsmasq/%I/resolv.conf --conf-dir=/opt/router-config/dnsmasq/%I/conf.d
KillSignal=SIGTERM
KillMode=control-group
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
%I 是模板实例化后,被替换的名称,例如,dnsmasq@lan.service , %I 就会被替换成 lan
软连接新建一个实例,这个服务是针对 lan 网卡的。创建 dnsmasq 配置存放的文件夹,我放在 /opt/router-config/dnsmasq/lan/ 下,
# 针对lan创建dnsmasq服务软连接,实例化模板
sudo ln -s /etc/systemd/system/dnsmasq@.service /etc/systemd/system/dnsmasq@lan.service
# 针对lan创建网卡的配置文件夹
sudo mkdir -p /opt/router-config/dnsmasq/lan/
# 创建dnsmasq配置文件
sudo touch /opt/router-config/dnsmasq/lan/dnsmasq.conf
# 创建租约记录文件(分配的客户端,都会被记录到这)
sudo touch /opt/router-config/dnsmasq/lan/dnsmasq.leases
# 创建静态分配的IP主机配置(dhcp-host)
sudo mkdir -p /opt/router-config/dnsmasq/lan/
# 创建额外配置目录conf.d
sudo mkdir -p /opt/router-config/dnsmasq/lan/conf.d
# 创建自定义的resolv.conf文件
sudo touch /opt/router-config/dnsmasq/lan/resolv.conf
# 创建日志存放的文件夹
sudo mkdir -p /var/log/dnsmasq
# 创建pid文件
sudo touch /run/dnsmasq@lan.pid
-
/var/log/dnsmasq为日志文件夹,文件夹下,网卡名.log为不同服务实例独立的日志。例如lan.log -
/run/dnsmasq@lan.pid为守护进程的pid记录文件。 -
/opt/router-config/dnsmasq/lan/目录结构如下:
lan/
├── conf.d
│ └── anti-ad-for-dnsmasq.conf
├── dnsmasq.conf
├── dnsmasq.leases
├── hosts.d
│ └── phone.ip
└── resolv.conf
-
hosts.d文件夹记录了绑定mac分配IP的配置。 -
conf.ddnsmasq服务的补充配置,这里用来设定屏蔽广告域名。(anti-ad域名屏蔽列表)
配置说明:
--except-interface 排除监听的网卡,此处设定不监听lo(127.0.0.1)。
--pid-file 守护进程的pid文件路径,此处systemd.service需要通过pid文件确定主进程的PID,精确控制停止进程。
--log-facility 服务日志保存路径
--interface dnsmasq服务绑定的网卡名,模板用%I绑定
--conf-file 配置文件的路径
--dhcp-leasefile 租约记录文件的路径,这个文件由dnsmasq自己管理,我们不改动内容
--dhcp-hostsfile 针对特定的mac,分配ip绑定的主机配置,如果是文件夹,则读取文件夹下所有的文件,此处使用的是文件夹,一个文件对应一个主机。
--resolv-file 自定义resolv.conf路径,上游DNS服务器的配置文件,此处是阿里云的dns
--conf-dir 导入目的目录下的所有配置文件,可以用来导入额外的配置,例如屏蔽部分域名。
dnsmasq.conf配置文件格式,和命令行参数保持一致,但是不同的地方是,没有--前缀,例如port = 53等价命令行--port=53,一行一个参数,对于没有右值的,则直接填左值,例如log-dhcp等价命令行参数--log-dhcp。其他的选项就可以根据manpage来配置,主要分成两部分,一部分配置dns服务器的,另外一部分则是关于DHCP的配置。此处只配置DHCP部分。
主配置文件内容:
# /opt/router-config/dnsmasq/lan/dnsmasq.conf
# DNS服务监听的端口,一般设置成53,绑定的地址为网卡的ip
port = 53
listen-address=192.168.31.1
# 缓存条目1000条
cache-size=10000
# DNS查询所有上游的服务器
all-servers
# 允许dbus总线
enable-dbus
# 本地hosts域名
bogus-priv
##########DHCP#####################
# DHCP 记录日志
log-dhcp
# dhcp选项 router为默认网关
dhcp-option=option:router, 192.168.31.1
# netmask 子网掩码
dhcp-option=option:netmask, 255.255.255.0
# domain
dhcp-option=option:domain-name, "my-router"
# dhcp分配给客户端的dns服务器
dhcp-option=option:dns-server, 192.168.31.1
# MTU值
dhcp-option=option:mtu, 1500
# 动态分配ip的范围,从2~254,租约时间为10小时
dhcp-range=192.168.31.2, 192.168.31.254, 10h
更多dhcp-option的选项可以通过dnsmasq --help dhcp查询到。
/opt/router-config/dnsmasq/lan/resolv.conf 内容(它定义了上游查询服务器,最多只能使用2个):
nameserver 223.5.5.5 223.6.6.6
MYCOMPUTER内容,针对mac地址为 23:33:33:33:33:44 的主机固定分配IP为 192.168.31.5
/opt/router-config/dnsmasq/lan/hosts.d/MYCOMPUTER 文件内容:
23:33:33:33:33:44, 192.168.31.5
文件格式是 --dhcp-host 选项的右值,以上相当于 --dhcp-host=23:33:33:33:33:44, 192.168.31.5 ,它可以是IPv4的,也可以是IPv6的,具体参考manpage。也是一行一个参数,不同的主机,可以分开不同的文件写配置,也会被读入。
文件配置完毕后,需要尝试启动 dnsmasq@lan.service ,并且允许它开机自启。
sudo systemctl daemon-reload
sudo systemctl start dnsmasq@lan.service
# 查看服务工作状况
sudo systemctl status dnsmasq@lan.service
# 允许开机自启
sudo systemctl enable dnsmasq@lan.service
TODO:
-
IPv6分配,由于IPv4和IPv6的DHCP分配地址方式不一样,具体详细的选项,还需要琢磨下手册。
-
网卡启动和关闭时,通过udev规则触发服务重启
笔记最后更新时间:2021-04-02