Linux 系统开启无线共享,使用同一个无线网卡,可以实现 “wifi -> wifi热点” 的共享。Linux 发行版为 Arch Linux,init 是 systemd。另外,使用这里的配置,能够把任意网络连接共享到 wifi 热点,比如“有线 -> wifi热点”、“USB网卡 -> wifi热点”等等。
¶0、查看基本信息
运行iw list
查看输出信息
Supported interface modes:
* AP
...
valid interface combinations:
* #{ managed } <= 2048, #{ AP, mesh point } <= 8, #{ P2P-client, P2P-GO } <= 1,
total <= 2048, #channels <= 1, STA/AP BI must match
* AP
表明网卡支持开启热点。#{AP,mesh point} <= 8
,表示网卡可以在连接其他热点的同时开启热点,最多可有8对(具体含义我不是很清楚)。#channels <= 1
,表示网卡最多能够在一个频道上同时工作。(我这的网卡只有单天线,一些多天线网卡可以同时在多个频道工作)
得到了上面的网卡硬件信息,接下来运行iwconfig
,查看网络接口信息
eth0 : no wireless extensions.
wlan0 : flags<...>,mtu ...
inet ...
Rx...
Tx...
lo : no wireless extensions.
默认的无线接口是wlan0
¶1、新建虚拟无线网络接口(interface)
终端执行iw list
,第一行输出无线网卡名称
Wiphy phy0
得到物理无线网卡名称phy0
,然后新建此无线网卡上的接口为wlan0_ap
,addr
指定此接口的 MAC 地址(可根据具体需要自行指定)。运行下面的命令
# iw phy phy0 interface add wlan0_ap type managed addr 12:34:56:ab:cd:ef
再解除NetworkManager
对这个接口的管理,修改/etc/NetworkManager/NetworkManager.conf
,在[Keyfile]
下增加这一行unmanaged-devices=mac:
,mac:
后面填写刚刚的 MAC 地址。
¶2、配置hostapd
hostapd 用以指定建立热点的具体设置,加载设备驱动等。新建或编辑/etc/hostapd/hostapd.conf
(hostapd配置文件,具体目录根据情况决定)
ssid=Arch_Linux
utf8_ssid=1
wpa_passphrase=archlinux
interface=wlan0_ap
auth_algs=3
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
rsn_pairwise=CCMP
driver=nl80211
country_code=UK
hw_mode=g
ieee80211n=1
wmm_enabled=1
channel=6
ht_capab=[HT40+][SHORT-GI-20][SHORT-GI-40]
ssid=Arch_Linux
填写热点名称为"Arch_Linux"。uft8_ssid=1
,utf8 编码热点名称,避免在有些设备上出现乱码。wpa_passphrase
密码interface=wlan0_ap
填写刚刚新建的那个虚拟接口"wlan0_ap"driver
填写使用的驱动,可以通过网卡型号 google 查找 linux 需要的驱动。hw_mode=g
热点使用 802.11g 模式。(即使是使用 n 模式也需要填写为g
,因为 n 模式是在 g 模式的基础上进行展频)ieee80211n=1
和wmm_enabled=1
,保证能够使用 n 模式。channel
使用频道,ht_capab
是展频相关设置,关于二者的具体关系可查看 hostapd 官方文档。
¶注:若channel <= 1
请看这里
在“0、查看基本信息”中,如果#channels
大于1,则不需要这部分配置;小于等于1则需要,保证频道(channel 选项)一致,否则开启的热点和已经连上的 wifi 会发生频道冲突,二者随机掉线。
新建保存/etc/hostapd/pre-hostapd.sh
如下,然后 root 运行chmod +x /etc/hostapd/pre-hostapd.sh
添加执行权限。
#!/bin/bash
WIFI_STAT=`iw dev wlan0 link`
HOSTAPD_CONF="/etc/hostapd/hostapd.conf"
CHANNEL_CONN=`iw dev wlan0 info | grep channel | awk '{print $2}'`
# delete previous channel settings
sed -ie '/channel/d' $HOSTAPD_CONF
sed -ie '/ht_capab/d' $HOSTAPD_CONF
if [[ $WIFI_STAT == "Not connected." ]]; then
echo "channel=6" >> $HOSTAPD_CONF;
echo "ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]" >> $HOSTAPD_CONF
elif (( $CHANNEL_CONN >= 1 && $CHANNEL_CONN <= 7 )); then
echo "channel=$CHANNEL_CONN" >> $HOSTAPD_CONF;
echo "ht_capab=[HT40+][SHORT-GI-20][SHORT-GI-40]" >> $HOSTAPD_CONF;
elif (( $CHANNEL_CONN >= 5 && $CHANNEL_CONN <= 13 )); then
echo "channel=$CHANNEL_CONN" >> $HOSTAPD_CONF;
echo "ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]" >> $HOSTAPD_CONF;
fi;
¶3、配置内网DHCP服务
注意,这里使用的包名称是dhcpd
,并不是dhcpcd
!前者是服务端,后者是客户端!
- 新建或编辑 dhcpd 配置文件
/etc/dhcpd.conf
如下
option domain-name-servers 8.8.8.8, 8.8.4.4;
option routers 10.0.0.100;
option subnet-mask 255.255.255.0;
subnet 10.0.0.0 netmask 255.255.255.0 {
range 10.0.0.150 10.0.0.250;
}
domain-name-servers
指定dns服务器,根据需要自行指定。routers
将虚拟网卡wlan0_ap
的内网地址指定为10.0.0.100
(请务必使用保留地址以避免冲突)。subnet-mask
指定掩码,决定内网ip范围。range
指定实际可用的内网ip范围。
运行
# ip addr add 10.0.0.100/24 dev wlan0_ap
,为虚拟网卡绑定内网地址10.0.0.100
(和上面指定的地址要一致)。dhcpd 默认在所有接口生效,这里只需要它在虚拟接口生效。新建文件
/etc/systemd/system/dhcpd4@.service
如下,保存后运行# systemctl daemon-reload
生效
[Unit]
Description=IPv4 DHCP server on %I
Wants=network.target
After=network-pre.target
Before=network.target
[Service]
Type=forking
PIDFile=/run/dhcpd4.pid
ExecStartPre=/usr/bin/ifconfig %I up
ExecStart=/usr/bin/dhcpd -4 -q -pf /run/dhcpd4.pid %I
KillSignal=SIGINT
[Install]
WantedBy=multi-user.target
¶4、配置iptables NAT转发
iptables -t nat -A POSTROUTING -j MASQUERADE
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED
iptables -A FORWARD -i wlan0_ap -j ACCEPT
iptables-save > /etc/iptables/iptables.rules
root 执行以上命令保存 iptables 规则。注意,这里的规则实际上是“全能”的共享方式,不仅保证“wifi -> wifi热点”的共享,也能够“有线 -> wifi热点”、“USB网卡 -> wifi热点”等方式共享。
¶5、开启内核转发功能
运行# sysctl net.ipv4.ip_forward=1
。在 Arch Linux 中需要将这个规则写入文件,防止重启失效。把net.ipv4.ip_forward=1
写入/etc/sysctl.d/30-ipforward.conf
文件。
¶6、保存虚拟接口信息
Arch Linux 使用 udev 来加载设备,因此每次重启后,之前新建的虚拟接口会失效。可以用一个 systemd 服务模块来解决问题。新建文件/etc/systemd/system/iw-interface-add@.service
如下,保存后运行# systemctl daemon-reload
生效
[Unit]
Description=Add interface %i
Wants=network.target
Before=network.target
[Service]
Type=oneshot
ExecStartPre=/usr/bin/iw phy phy0 interface add %i type managed addr 12:34:56:ab:cd:ef
ExecStart=/usr/bin/ip addr add 10.0.0.100/24 dev %i
[Install]
WantedBy=multi-user.target
再修改之前创建的 /etc/systemd/system/dhcpd4@.service
如下,保存后运行# systemctl daemon-reload
生效
[Unit]
Description=Add interface %i and start IPv4 DHCP server on it
Wants=network.target
After=iw-interface-add@%i.service network-pre.target
Before=network.target
Requires=iw-interface-add@%i.service
[Service]
Type=forking
PIDFile=/run/dhcpd4.pid
ExecStartPre=/usr/bin/ifconfig %i up
ExecStart=/usr/bin/dhcpd -4 -q -pf /run/dhcpd4.pid %i
KillSignal=SIGINT
[Install]
WantedBy=multi-user.target
¶7、整合服务
为了方便,可将所有启动命令整合进 hostapd 的 systemd 模块。编辑/usr/lib/systemd/system/hostapd.service
如下,保存后运行# systemctl daemon-reload
使修改生效。
[Unit]
Description=Hostapd IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
After=network.target
Requires=dhcpd4@wlan0_ap.service iptables.service
BindsTo=dhcpd4@wlan0_ap.service iptables.service
[Service]
ExecStartPre=/etc/hostapd/pre-hostapd.sh
ExecStart=/usr/bin/hostapd /etc/hostapd/hostapd.conf
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
- 其中
ExecStartPre=/etc/hostapd/pre-hostapd
是#channel <= 1
需要的配置,若大于1则需要删除这一行。
现在运行# systemctl start hostapd.service
可立即开启 wifi 共享。