hostapd实现无线热点¶
我曾经使用 使用create_ap工具创建软AP 实现了简单的无线AP提供多个设备共享上网,不过,最近 配置hostapd实现无线热点(失败记录) 。不过,我参考了多个文档后,决定在 树莓派Raspberry Pi 4 上(也就是我的 ARM架构Kubernetes 的master节点)上部署一个无线热点。
激活AP和管理模式并用的WiFi¶
通常情况下,我们都使用无线网卡作为无线网络的 “客户端” 模式去连接一个无线AP,这种模式称为 managed
设备。但是,如果要将Linux主机的无线网卡作为一个WiFi热点,则称为AP模式。由于我们只有一个无线网卡,所以我们需要配置树莓派上的无线网卡 wlan0
同时工作在AP和管理模式下,以便能够既连接Internet,同时共享AP给其他设备使用,实现一个无线路由器功能。
在树莓派启动时,无线网卡被识别为 wlan0
,我们需要创建一个udev规则,使得无线网卡 wlan0
启动时同时能够创建一个 managed
模式的虚拟网卡。
创建
/etc/udev/rules.d/70-persistent-net.rules
SUBSYSTEM=="ieee80211", ACTION=="add|change", ATTR{macaddress}=="b8:27:eb:ff:ff:ff", KERNEL=="phy0", \ RUN+="/sbin/iw phy phy0 interface add ap0 type __ap", \ RUN+="/bin/ip link set ap0 address b8:27:eb:ff:ff:ff"
注意,这里的mac地址必须是无线网卡的mac地址,通过 iw dev
命令可以查看mac地址,这里创建的虚拟网络设备是 ap0
。
备注
这步我没有成功,所以我最后还是手工执行命令来激活ap0:
/sbin/iw phy phy0 interface add ap0 type __ap
/bin/ip link set ap0 address b8:27:eb:ff:ff:ff
安装DNSmasq和Hostapd¶
Dnsmasq 为WiFi AP 提供DHCP服务
Hostapd 基于驱动配置来定义无线AP的物理操作
安装:
sudo apt install dnsmasq hostapd
这里默认启动的dnsmasq服务只启动了dns服务,不会启动dhcp,所以下一步我们需要配置
修改
/etc/dnsmasq.conf
添加如下配置:interface=lo,ap0,eth0 no-dhcp-interface=lo,wlan0 bind-interfaces server=8.8.8.8 domain-needed bogus-priv dhcp-range=192.168.10.50,192.168.10.150,12h
修订
/etc/hostapd/hostapd.conf
ctrl_interface=/var/run/hostapd ctrl_interface_group=0 interface=ap0 driver=nl80211 ssid=YourApNameHere hw_mode=g channel=11 wmm_enabled=0 macaddr_acl=0 auth_algs=1 wpa=2 wpa_passphrase=YourPassPhraseHere wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP CCMP rsn_pairwise=CCMP
如果要隐藏SSID,可以添加一行:
ignore_broadcast_ssid=1
修改
/etc/default/hostapd
DAEMON_CONF="/etc/hostapd/hostapd.conf"
修改
/etc/network/interfaces
来支持AP:auto lo iface lo inet loopback auto ap0 allow-hotplug ap0 iface ap0 inet static address 192.168.10.1 netmask 255.255.255.0 hostapd /etc/hostapd/hostapd.conf
备注
这里没有配置 eth0
和 wlan0
,因为我已经配置了使用 netplan网络配置 来管理这两个设备。
备注
不需要单独启动hostapd服务,这个服务是通过启动网络接口来启动的。
手工启动¶
手工启动虚拟网卡
ap0
(也就是 udev 规则中命令)/sbin/iw phy phy0 interface add ap0 type __ap /bin/ip link set ap0 address b8:27:eb:ff:ff:ff
重启一次
ap0
sudo ifdown --force ap0 sudo ifup ap0
启动以后可以看到接口:
ip addr
显示输出:
...
3: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
link/ether b8:27:eb:ff:ff:ff brd ff:ff:ff:ff:ff:ff
inet6 fe80::96eb:cdff:fe8e:eb3f/64 scope link
valid_lft forever preferred_lft forever
...
9: ap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether b8:27:eb:ff:ff:ff brd ff:ff:ff:ff:ff:ff
inet 192.168.10.1/24 brd 192.168.10.255 scope global ap0
valid_lft forever preferred_lft forever
inet6 fe80::96eb:cdff:fe8e:eb3f/64 scope link
valid_lft forever preferred_lft forever
可以看到之前 wlan0
上通过 netplan网络配置 获得的无线IP地址消失了,而我们重新启动的 ap0
则已经分配了静态IP地址。
再次执行
netplan
恢复wlan0的无线IP:netplan apply
则再次观察 ip addr
输出可以看到 wlan0
和 ap0
都正确获得IP地址:
3: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
link/ether b8:27:eb:ff:ff:ff brd ff:ff:ff:ff:ff:ff
inet6 fe80::96eb:cdff:fe8e:eb3f/64 scope link
valid_lft forever preferred_lft forever
...
9: ap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether b8:27:eb:ff:ff:ff brd ff:ff:ff:ff:ff:ff
inet 192.168.10.1/24 brd 192.168.10.255 scope global ap0
valid_lft forever preferred_lft forever
inet6 fe80::96eb:cdff:fe8e:eb3f/64 scope link
valid_lft forever preferred_lft forever
现在我们重新启动dnsmasq为我们的
ap0
提供DHCP服务:systemctl restart dnsmasq
通过 systemctl status dnsmasq
可以看到分配DHCP:
● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server
Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2021-04-27 23:32:39 CST; 28s ago
Process: 2542555 ExecStartPre=/usr/sbin/dnsmasq --test (code=exited, status=0/SUCCESS)
Process: 2542564 ExecStart=/etc/init.d/dnsmasq systemd-exec (code=exited, status=0/SUCCESS)
Process: 2542574 ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf (code=exited, status=0/SUCCESS)
Main PID: 2542573 (dnsmasq)
Tasks: 1 (limit: 2101)
Memory: 2.0M
CGroup: /system.slice/dnsmasq.service
└─2542573 /usr/sbin/dnsmasq -x /run/dnsmasq/dnsmasq.pid -u dnsmasq -7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new --local-service --trust-anchor=.,20326,8,2,e06d4>
Apr 27 23:32:39 pi-master1 dnsmasq[2542573]: started, version 2.80 cachesize 150
Apr 27 23:32:39 pi-master1 dnsmasq[2542573]: compile time options: IPv6 GNU-getopt DBus i18n IDN DHCP DHCPv6 no-Lua TFTP conntrack ipset auth nettlehash DNSSEC loop-detect inoti>
Apr 27 23:32:39 pi-master1 dnsmasq-dhcp[2542573]: DHCP, IP range 192.168.10.50 -- 192.168.10.150, lease time 12h
Apr 27 23:32:39 pi-master1 dnsmasq-dhcp[2542573]: DHCP, sockets bound exclusively to interface ap0
Apr 27 23:32:39 pi-master1 dnsmasq[2542573]: using nameserver 8.8.8.8#53
Apr 27 23:32:39 pi-master1 dnsmasq[2542573]: reading /etc/resolv.conf
Apr 27 23:32:39 pi-master1 dnsmasq[2542573]: using nameserver 8.8.8.8#53
Apr 27 23:32:39 pi-master1 dnsmasq[2542573]: using nameserver 127.0.0.53#53
Apr 27 23:32:39 pi-master1 dnsmasq[2542573]: read /etc/hosts - 10 addresses
Apr 27 23:32:39 pi-master1 systemd[1]: Started dnsmasq - A lightweight DHCP and caching DNS server.
万事具备,我们现在可以启动 iptables masquerade
sudo sysctl -w net.ipv4.ip_forward=1 sudo iptables -t nat -A POSTROUTING -s 192.168.10.0/24 ! -d 192.168.10.0/24 -j MASQUERADE
问题排查¶
我遇到一个问题,客户端可以正确连接到AP并且获得IP地址,也能够ping通网关(即无线AP的地址 192.168.10.1),而且检查DNS解析也正确(DNS是192.168.10.1,即通过该路由器的dnsmasq代理解析正确)。
但是,无法ping通外网,也无法和外网通讯
检查
iptables -t nat -L
显示:Chain POSTROUTING (policy ACCEPT) target prot opt source destination KUBE-POSTROUTING all -- anywhere anywhere /* kubernetes postrouting rules */ MASQUERADE all -- 172.17.0.0/16 anywhere RETURN all -- pi-master1/16 pi-master1/16 MASQUERADE all -- pi-master1/16 !base-address.mcast.net/4 random-fully RETURN all -- !pi-master1/16 pi-master1/24 MASQUERADE all -- !pi-master1/16 pi-master1/16 random-fully MASQUERADE all -- 192.168.10.0/24 !192.168.10.0/24
这里可以看到很多NTA规则,原因是这台服务器同时是kubernetes集群的master管控主机。
我怀疑是顺序原因,所以改为在头部插入:
iptables -t nat -L POSTROUTING --line-numbers -n
显示:
Chain POSTROUTING (policy ACCEPT)
num target prot opt source destination
1 KUBE-POSTROUTING all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes postrouting rules */
2 MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
3 RETURN all -- 10.244.0.0/16 10.244.0.0/16
4 MASQUERADE all -- 10.244.0.0/16 !224.0.0.0/4 random-fully
5 RETURN all -- !10.244.0.0/16 10.244.0.0/24
6 MASQUERADE all -- !10.244.0.0/16 10.244.0.0/16 random-fully
7 MASQUERADE all -- 192.168.10.0/24 !192.168.10.0/24
在第二行插入:
iptables -t nat -I POSTROUTING 2 -s 192.168.10.0/24 ! -d 192.168.10.0/24 -j MASQUERADE
但是依然无效
我尝试了清理nat规则:
iptables -t nat -F
但是发现系统会自动恢复添加以下NAT规则:
RETURN all -- pi-master1/16 pi-master1/16
MASQUERADE all -- pi-master1/16 !base-address.mcast.net/4 random-fully
RETURN all -- !pi-master1/16 pi-master1/24
MASQUERADE all -- !pi-master1/16 pi-master1/16 random-fully
然后即使加了以下nat规则也没有效果:
MASQUERADE all -- 192.168.10.0/24 !192.168.10.0/24
我尝试删除:
iptables -t nat -D POSTROUTING 1
...
但是系统不断自动刷新添加,最终么有成功解决
自动化脚本¶
以上手工命令我们可以综合成一个脚本 /home/pi/start-ap-managed-wifi.sh
#!/bin/bash
sleep 30
sudo ifdown --force ap0 && sudo ifup ap0
sudo netplan apply
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -s 192.168.10.0/24 ! -d 192.168.10.0/24 -j MASQUERADE
sudo systemctl restart dnsmasq
然后配置一个启动cron:
sudo crontab -e
添加内容:
@reboot /home/pi/start-ap-managed-wifi.sh
这样每次重启都会执行上述脚本(脚本第一行添加 sleep 30
是为了估算启动到网卡时间)