请稍侯

将树莓派打造成无线路由器

19 July 2015

家里有个很挫的无线路由器,不能刷 OpenWRT,没什么可玩性,只好拿树莓派开刀了,顺便学点网络相关的知识。

既然是无线路由器,除了树莓派以外还需要一张无线网卡,本人使用的是 EP-N8508GS,这是一款廉价的无线网卡,支持软 AP,但是无法使用 aircrack,如果想用来破解无线网络,还是不要买这款了。如果你用的是其他型号的无线网卡,本文的大部分步骤应该仍然有效。如果是用的 360、百度、小米之类的随身 WiFi,可能有驱动问题,请参考这篇文章解决。

本文的基本思路是,让树莓派利用有线网卡连接到网络,利用无线网卡创建 AP,然后通过 iptables 规则在两个网卡之间转发数据包。如果只用无线网卡,可以参考 Arch Wiki

一、安装并配置 hostapd

为了使用无线网卡 AP 功能,需要安装 hostpad。如果你的芯片型号在支持之列,请直接从软件源安装:

sudo apt-get install hostapd

EP-N8508GS 使用的芯片型号是 Realtek RTL8188CUS,不能使用软件源里面的 hostapd,放狗搜发现国外大神的这篇文章,使用 Realtek 官方提供的 hostapd 源码编译,经测试,工作正常。大致步骤如下:

从 GitHub 下载最新源码并解压:

wget https://github.com/jenssegers/RTL8188-hostapd/archive/v2.0-beta.tar.gz
tar -zxvf v2.0-beta.tar.gz

进入源码目录,编译安装:

cd RTL8188-hostapd-2.0-beta/hostapd
sudo make
sudo make install

(建议养成良好的习惯,不要直接 make install,先使用 checkinstall 打包成 deb,然后再安装,方便管理,此处略过。)

然后打开 hostapd 的配置文件 /etc/hostapd/hostapd.conf,修改 ssidwpa_passphrase 为 WiFi 热点的名称和密码,比如我的:

# Basic configuration

interface=wlan0
ssid=Raspberry_Pi
channel=6
#bridge=br0

# WPA and WPA2 configuration

macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=123456
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
wmm_enabled=0

# Hardware configuration

driver=rtl871xdrv
ieee80211n=1
hw_mode=g
device_name=RTL8188CUS
manufacturer=Realtek

如果使用软件源的 hostapd,请修改 /etc/default/hostapd,设置 conf 文件路径:

DAEMON_CONF="/etc/hostapd/hostapd.conf"

最后,重启 hostapd 服务,并设置开机启动:

sudo service hostapd restart
sudo update-rc.d hostapd defaults

二、安装并配置 udhcpd

为了让连到热点的设备能通过 DHCP 获取 IP,需要安装 DHCP 服务程序,可以使用 udhcpd 或 dnsmasq。安装 udhcpd:

sudo apt-get install udhcpd

然后打开 udhcpd 配置文件 /etc/udhcpd.conf,修改 startend 为 DHCP 分配的 IP 段的起始和结束 IP,并修改 opt dnsopt subnetopt router 等选项设置 DNS、子网掩码、路由器 IP,例如:

start           192.168.42.2        #default: 192.168.0.20
end             192.168.42.20       #default: 192.168.0.254

interface       wlan0               #default: eth0

remaining       yes                 #default: yes

opt     dns     192.168.42.1
option  subnet  255.255.255.0
opt     router  192.168.42.1
option  dns     8.8.8.8             # appened to above DNS servers
option  lease   864000              # 10 days of seconds

这个地方我设置路由器 IP 为 192.168.42.1,并设置分配的 IP 范围为 192.168.42.2 - 192.168.42.20,所有设备都在 192.168.42.0/24 这个子网内。

注意:上面设置 dns 服务器地址为 192.168.42.1 是因为我在树莓派上搭建了一个 DNS 服务器,如果你没有,请设置成其他公用 DNS,比如 114.114.114.114

接着修改 /etc/default/udhcpd,注释掉 DHCPD_ENABLED="no" 这一行。

重启 udhcpd 服务,并设置开机启动:

sudo service udhcpd restart
sudo update-rc.d udhcpd defaults

三、配置 iptables 和网络接口

打开网络接口配置文件 /etc/network/interfaces,设置 wlan0 为静态 ip,如下:

auto lo

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0

iface wlan0 inet static
    address 192.168.42.1
    netmask 255.255.255.0
#    gateway 192.168.1.1
#    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

iface default inet dhcp

然后使配置生效:

sudo ifdown wlan0
sudo ifup wlan0

接着开始配置 iptables。修改 /etc/sysctl.conf,打开内核 IP 转发,在末尾添加:

net.ipv4.ip_forward=1

然后,添加 iptables 规则,将 wlan0 的包通过 eth0 转发:

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT

由于 iptables 设置重启后将消失,常用的方法是先保存下来:

sudo sh -c "iptables-save > /etc/iptables.ipv4.nat"

然后启动时加载,编辑 /etc/network/interfaces,添加下面这一行:

up iptables-restore < /etc/iptables.ipv4.nat

也可以写一个启动脚本 /etc/init.d/iptables,执行以上 iptables 命令:

#!/bin/bash
### BEGIN INIT INFO
# Provides:          iptables
# Required-Start:    mountkernfs $local_fs
# Required-Stop:     mountkernfs $local_fs
# X-Start-Before:    networking
# X-Stop-After:      networking
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Iptables
# Description:       Debian init script for iptables
### END INIT INFO

. /lib/lsb/init-functions

function do_start {
    log_daemon_msg "Starting iptables service" "iptables"
    # hostapd rules
    if ls /etc/rc*.d/*hostapd; then
        iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
        iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
        iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
    fi
    log_end_msg $?
}

function do_stop {
    log_daemon_msg "Stopping iptables service" "iptables"
    # hostapd rules
    if ls /etc/rc*.d/*hostapd; then
        iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
        iptables -D FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
        iptables -D FORWARD -i wlan0 -o eth0 -j ACCEPT
    fi
    log_end_msg $?
}

case "$1" in
    start)      do_start;;
    stop)       do_stop;;
    restart)    do_stop; do_start;;
    *)          echo "Usage: /etc/init.d/iptables {start|stop|restart}"; exit 1;;
esac

exit 0

然后,增加可执行权限,并设置开机自动执行:

sudo chmod +x /etc/init.d/iptables
sudo update-rc.d iptables defaults

以上,AP 的配置就基本完成了,重启一下,看看手机或笔记本是不是能连上你的 WiFi 热点。

四、AP 模式和普通模式切换

如果你想切换 AP 模式和普通模式,请保留 /etc/network/interfaces 里面注释掉的两行,并使用上面的启动脚本的方式配置 iptables。

打开 /etc/wpa_supplicant/wpa_supplicant.conf,设置 WiFi 的名称、密码以自动连接:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="PHICOMM_68E238"
    proto=RSN
    key_mgmt=WPA-PSK
    pairwise=CCMP TKIP
    group=CCMP TKIP
    psk="123456"
}

最后,可使用下面的脚本切换(需要 root 权限):

#!/bin/bash

if [ "$1" = 'on' ]; then
    service hostapd start
    update-rc.d hostapd defaults
    iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
    ifdown wlan0
    sed -i -e 's/^\( *address\) 192\.168\.1\.120$/\1 192\.168\.42\.1/' \
           -e 's/^\( *gateway .*\)$/#\1/' \
           -e 's/^\( *wpa-conf .*\)$/#\1/' \
           /etc/network/interfaces
    ifup wlan0
elif [ "$1" = 'off' ]; then
    service hostapd stop
    update-rc.d hostapd remove
    iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
    iptables -D FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -D FORWARD -i wlan0 -o eth0 -j ACCEPT
    ifdown wlan0
    sed -i -e 's/^\( *address\) 192\.168\.42\.1$/\1 192\.168\.1\.120/' \
           -e 's/^#\( *gateway .*\)$/\1/' \
           -e 's/^#\( *wpa-conf .*\)$/\1/' \
           /etc/network/interfaces
    ifup wlan0
else
    echo "usage: $(basename "$0") <on|off>"
    exit 1
fi

此处,普通模式同样使用静态 IP:192.168.1.120

如果 ipdownifup 有问题,过一会儿再依次执行 ipdownifup,或者直接重启。

如果想继续给树莓派加上过滤网页和视频广告、科学上网等功能请阅读下篇

参考: