NetworkManager Hostapd Dnsmasq 单臂路由

 · 3 分钟
Last updated: 2022-11-13
Table of contents

动机

手上有一个设备只有一个网口,但我又不想用USB网卡占据宝贵的接口。配合交换机还能依靠交换机走内网流量、接入多个设备。

说那么多其实某种意义上就是想折腾XD。

流程

大概分为交换机配置和路由器(设备)配置吧。

  • 交换机
    • 划分VLAN
  • 路由器
    • 装系统
    • 配置VLAN
    • 配置DHCP服务和DNS
    • 配置无线网

交换机配置VLAN

路由器直连的口设置为 Trunk,另外划一个口到另一个VLAN(用作WAN)。除了路由器的网口,其余均设置为 Untagged。

# example
# T: Tagged/Trunk
# U: Untagged
# X: disabled
# Port 1: router
# Port 2: WAN
# Port 3-5: LAN
Port  1 2 3 4 5
VLAN1 T X U U U
VLAN2 T U X X X

单臂路由拨号上网

你应该有个交换机,这样可以配置 802.11Q 标准的VLAN。这里将VLAN1设置为内网,VLAN2设置为WAN,务必和交换机配置一致。 下面给出的例子是用 NetworkManager 划分VLAN并拨号上网的示例。

# vlan & pppoe, router-on-a-stick model, change ifname accordingly
nmcli con add type bridge ifname br0 con-name LAN stp no autoconnect yes
nmcli con add type vlan ifname vlan1 con-name vlan-internal id 1 dev eth0 master br0
nmcli con add type vlan ifname vlan2 con-name vlan-external id 2 dev eth0
nmcli con add type pppoe ifname pppoe0 con-name WAN autoconnect yes pppoe.parent vlan2 username 'nicename' password 'veryhardpassword1234'

PPPoE路由自动设置脚本

因为一些我之前没搞清楚的原因,PPPoE拨号上网后需要配置路由才能正常上网,然而 NetworkManager 没有自动处理(或者说处理得不好)。 因而我写了一个自动在PPPoE连接成功后添加对应路由的 dispatcher (相当于NetworkManager的钩子/hook脚本)。 不过现在好像没有这个问题了?

#!/usr/bin/env bash
# /etc/NetworkManager/dispatcher.d/30-auto-route-for-pppoe.sh

interface=$1
event=$2
target_interfaces=("pppoe0")

for target in ${target_interfaces[@]} ; do

if [[ $interface == $target ]] ; then

case "$event" in
    up)
        # startup
        ip route delete default dev $interface
        ip route delete default dev $DEVICE_IP_IFACE
        ip route add default via $IP4_GATEWAY dev $DEVICE_IP_IFACE proto static metric 99
        sysctl -p net.ipv4.conf.$DEVICE_IP_IFACE.forwarding=1
        ;;
    down)
        ip route delete default dev $interface
        ip route delete default dev $DEVICE_IP_IFACE
        ;;
    *)
        printf 'Unexpected event(%s) for interface(%s) !\n' $event $interface
        ;;
esac

fi

done

# vim:sw=4:ts=4:et:

配置dnsmasq

因为某些原因 1 2 ,需要用 systemctl edit dnsmasq 添加下面的配置以保证 NetworkManager 先完全启动。

[Unit]
After=NetworkManager-wait-online.service

Warning

如果有装 systemd-resolved,请务必禁用!

配置hostapd

贴一下我的部分配置

interface=wlp2s0
bridge=br0
driver=nl80211
ssid=AP-NAME
hw_mode=g
channel=3
wpa=2
wpa_passphrase=1234567890
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP
rsn_pairwise=CCMP

在 NetworkManager 配置中忽略 Hostapd 要用到的端口以免产生干扰。

# /etc/NetworkManager/conf.d/unmanaged.conf
[keyfile]
unmanaged-devices=interface-name:wlp2s0

调整启动顺序

严格顺序:NM->{Dnsmasq,Hostapd}

systemctl edit dnsmasq

添加以下内容

[Unit]
After=NetworkManager-wait-online.service

用networkmanager的dispatcher启动hostapd,否则hostapd会启动太早占用br0

#!/usr/bin/env bash
# auto trigger script for starting hostapd and dnsmasq

interface=$1
event=$2
target_interfaces=("br0")

for target in ${target_interfaces[@]} ; do

if [[ $interface == $target ]] ; then

case "$event" in
    up)
        # startup
    systemctl start hostapd
    systemctl start dnsmasq
        ;;
    down)
    systemctl stop hostapd
    systemctl stop dnsmasq
        ;;
    *)
        printf 'Unexpected event(%s) for interface(%s) !\n' $event $interface
        ;;
esac

fi

done

# vim:sw=4:ts=4:et:

Note

如果还存在奇怪的问题, 则禁用dnsmasq和hostapd服务的自动启动, 改用dispatcher脚本去启动

配置iptable

开放端口,让DHCP(67/68)、SSH(22)、http(80/443)、DNS(53)可达

  • TCP:22,53,80,443
  • UDP:53,67,68

别的可以参考 Simple Stateful Firewall但是别完全照抄!

其它调整

启用bbr拥塞控制算法

编辑 /etc/sysctl.conf 并添加如下内容:

net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr

以管理员权限执行 sysctl -p 重载配置中的信息。