使用树莓派3构建校园网关路由器


为什么我要采用树莓派3作为路由器

我原来的用的无线路由是WR841N, 刷了Openwrt, 用于锐捷认证和提供ipv4网络.
前些日子折腾在路由器后提供ipv6网络, 可是学校网络不支持relay mode, 因此只能在路由上配置NAT6.
然而NAT6是非常消耗资源的一项操作. 当北邮人PT下载跑满百兆带宽的时候, 路由器的负载就会上到5以上.
担心长时间路由器会HOLD不住, 所以萌生了购买了一个新的路由器的想法.
本来已经看好了MT7610a的小米路由mini, 但是转念一想为什么不用树莓派搭建一个网关呢.
成本并没有增加多少, 而且5V的供电也可以在没电之后继续使用移动电源使用.
更何况树莓派3的四核A53比起MT7610a的性能不知道好了多少倍.
以及我并不需要千兆无线, 而且MT7610a只有百兆有线.

除了树莓派3的其他选择

在同等价位来考虑, 其实香蕉派M2+其实是一个更好的选择.
香蕉派M2+的劣势下在于四核A7@1.2g比起树莓派3要差.
但是, 优势同样非常明显.
树莓派3的最大缺点就在于IO带宽, 其物理拓扑结构是主芯片引出一个USB2.0接口到网卡同时作为HUB引出四个USB口.
也就是说, 板载的网卡LAN9514和四个USB接口同时共用一个USB2.0的480Mbps带宽.
当需要进行大IO操作时, 劣势就明显的体现出来了.
香蕉派M2+的网卡以及两个USB口都是直连芯片的, 只受到AMBA带宽的限制.
根据我看到的实测数据大概可以达到60+MByte/s, 相比之下, 树莓派的实测数据只能到10+MByte/s.
如果需要更大的IO带宽, 那么最好还是右转上J1900这样的凌动x86, 大概也只要500左右.
除了IO带宽以外, 香蕉派M2+还板载8G emmc. 相比TF卡, 稳定性大大提升, 同时也省下买TF卡的钱.
不过我倒是有一大把闲置的TF卡, 其实倒不是什么问题.
以及, 在香蕉派上有官方提供的Android系统, 以后也可以改造成电视盒子使用.

至于, 为什么最后还是选择了树莓派...原因还是更好友好的社区支持嗯.
换而言之就是用的人多, 踩坑的概率小= =

硬件准备

树莓派3一只. USB有线网卡一只, TF卡8G一只, 5V2A电源一只(5V1A也可以)

开工

在系统的选择上, 我采用的是Openwrt的衍生系统LEDE.
根据官方Wiki的叙述, 大概就是Openwrt的一帮开发者看Openwrt的低效不爽, 自己另外开个新坑的感觉.
不过, 确实LEDE的内核版本会比Openwrt要新, 所以就用它了.

LEDE的下载地址: https://downloads.lede-project.org/snapshots/targets/brcm2708/bcm2710/
下载那个: lede-brcm2708-bcm2710-rpi-3-ext4-sdcard.img.gz 就好了√

安装请参考Openwrt Wiki: https://wiki.openwrt.org/toh/raspberry_pi_foundation/raspberry_pi
简述的话就是在Linux内:

dd if=lede-brcm2708-bcm2710-rpi-3-ext4-sdcard.img of=/dev/sd* bs=2M conv=fsync

值得注意的是, 这会更改TF卡的分区表, 如果有什么数据的话, 请做好备份.
默认的话, 会分出一个20M的/boot分区和一个256M的/分区. 显然没有很好的利用好TF卡的空间.
所以, 我们还需要重新对TF卡分个区. 这可以使用GParted做到:

sudo apt-get install gparted
sudo umount /media/username/* #使用GParted前先取消挂载
sudo gparted

只要File-Device选择TF卡, 然后右键分区, 选择Resize就可以调整分区大小了√

Wiki中还提供了一些有用的信息:
比如说可以通过GPIO连接串口:
115200 8N1

Pin 6Pin 8Pin 10
GroundTXRX

以及可以通过修改/boot/config.txt文件修改一些配置.

修改软件源

很遗憾, 官方默认的软件源在国内的普通网络情况下似乎是连不上的.
而且, 官方的软件是滚动更新的. 一旦换了内核版本简直就是噩梦...
特别是opkg还没有提供upgrade的功能_(:3」∠)_
所以, 我特意把我安装时的软件源镜像了一份存在了服务器上. 大概一共才500M不到吧√
地址是: http://raspberrypi.slkun.me/mirror/LEDE/20161119/
速度什么的另说...至少以后官方滚内核的时候, 可以保证还有旧的软件可以用.
服务会在我还在用这一版的前提下会一直提供的嗯.

新版的17.01和18.06已出, 该镜像不再维护

软件源的配置文件在: /etc/opkg/distfeeds.conf

src/gz reboot_core http://raspberrypi.slkun.me/mirror/LEDE/20161119/core/
src/gz reboot_base http://raspberrypi.slkun.me/mirror/LEDE/20161119/base
src/gz reboot_telephony http://raspberrypi.slkun.me/mirror/LEDE/20161119/telephony
src/gz reboot_packages http://raspberrypi.slkun.me/mirror/LEDE/20161119/packages
src/gz reboot_routing http://raspberrypi.slkun.me/mirror/LEDE/20161119/routing
src/gz reboot_luci http://raspberrypi.slkun.me/mirror/LEDE/20161119/luci
#src/gz reboot_usr http://raspberrypi.slkun.me/mirror/LEDE/20161119/usr

usr目录是打算放我自己编译的一些软件, 现阶段就是mentohust咯.
请手动下载安装, 目前还没有配置Packages信息.

网络配置

默认配置的树莓派的网口为lan口, 是一个静态的192.168.1.1的ip, 没有dhcp服务器也没有dhcp客户端.
而且默认配置的LEDE也没有安装luci, 只能通过SSH登录.
因此, 需要修改/etc/config/network文件将其修改成为dhcp客户端模式以能够连上网.

config interface 'loopback'
        option ifname 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option ula_prefix 'fd8f:4e62:2b25::/48'

config interface 'lan'
        option ifname 'eth0'
        option proto 'dhcp'

这样只要把树莓派的lan口连上可以上网的路由器就可以了.

LEDE内部配置

系统镜像准备好之后, 把TF卡插进树莓派, 然后上电.
通过查看路由器的DHCP表来获得树莓派的ip, 当然也可以在网络配置时采用静态ip.
但是需要注意配置正确的网关, 不然内网可以访问到树莓派, 但是树莓派不能通过路由上网.

硬件驱动

我用的USB网卡是ASIX AX88772B, 虽然很廉价, 但是基本上也能够跑满100M的带宽.
确认路由器可以连上网以后, 安装驱动:

opkg update
opkg install kmod-usb-net kmod-usb-asix

这样使用ifconfig就可以看到eth1的第二张网卡了.

安装Luci

opkg install luci luci-i18n-base-zh-cn luci-i18n-firewall-zh-cn luci-theme-material

安装一些实用工具

opkg install ipset vim-full git git-http zsh curl libustream-openssl
opkg install wpad

安装Mentohust

ipk包可以从镜像下的usr分类下下载.

opkg install mentohust luci-luci-app-mentohust

注意不要直接使用mentohust的交互式命令行输入用户名和密码.
该编译版本与shell不太兼容, 我也懒得去找为什么.
直接使用/etc/mentohust文件配置, 或者通过luci就好.

安装ipv6 NAT支持

opkg install kmod-ipt-nat6

添加启动时脚本到/etc/rc.local

#!/bin/sh /etc/rc.common

# For enable mentohust for sure at startup
MAX_TRIES=60
COUNT=1
PING_TEST=$(ping -w 3 www.baidu.com | grep "3 packets transmitted, 3 packets received")

# detecting internet is ok
while [ ! -n "$PING_TEST" ]
        do
        if [ $COUNT -gt $MAX_TRIES ]
        then
                logger -t MENTOHUST "Cannot access the Internet (reached retry limit $MAX_TRIES times)" && exit 1
        fi
        mentohust -k
        sleep 10
        mentohust -d
        sleep 60
        logger -t MENTOHUST "Try to connect the Internet... ($COUNT time)"
        COUNT=$((COUNT+1))
        PING_TEST=$(ping -w 3 www.baidu.com | grep "3 packets transmitted, 3 packets received")
done
logger -t MENTOHUST "Internet is accessible!"

# NAT6 init script for OpenWrt 
# Depends on package: kmod-ipt-nat6 ip6tables
# Ref:  https://wiki.openwrt.org/doc/howto/ipv6.nat6

MAX_TRIES=60
WAN6_NAME="wan6" 
WAN6_INTERFACE=$(uci get "network.$WAN6_NAME.ifname") 
LAN_ULA_PREFIX=$(uci get network.globals.ula_prefix)
PROBE=0
COUNT=1

# detecting ipv6
while [ $PROBE -eq 0 ]
        do
        if [ $COUNT -gt $MAX_TRIES ]
        then
                logger -t NAT6 "No IPv6 route found (reached retry limit $MAX_TRIES times)" && exit 1
        fi
        sleep 30
        logger -t NAT6 "detect IPv6 route... ($COUNT time)"
        COUNT=$((COUNT+1))
        PROBE=$(route -A inet6 | grep -c '::/0')
done

ip6tables -t nat -I POSTROUTING -s "$LAN_ULA_PREFIX" -o "$WAN6_INTERFACE" -j MASQUERADE
logger -t NAT6 "configure the IPv6 NAT table: $LAN_ULA_PREFIX at $WAN6_INTERFACE"

WAN6_GATEWAY=$(ifconfig "$WAN6_INTERFACE" | grep 'Global' | awk '{print $3}'| awk -F':' '{print $1":"$2":"$3":"$4"::1"}')
logger -t NAT6 "get the gateway of IPv6: $WAN6_GATEWAY"

route -A inet6 add default gw "$WAN6_GATEWAY" dev "$WAN6_INTERFACE"
logger -t NAT6 "set the gateway of IPv6: $WAN6_GATEWAY at $WAN6_INTERFACE"

logger -t NAT6 "IPV6 Configure done!"

exit 0

前一部分是刚开机时(早上来电时)如果发现认证不成功没有网, 就反复尝试认证直到成功为止.
第二部分是判断网络是否存在ipv6, 如果存在则建立ipv6 NAT转发.

配置网络

最后需要把网口做出合理的分配. /etc/config/network

config interface 'loopback'
    option ifname 'lo'
    option proto 'static'
    option ipaddr '127.0.0.1'
    option netmask '255.0.0.0'

config globals 'globals'
    option ula_prefix '1111:2222:3333:4444::/64'

config interface 'lan'
    option ifname 'eth1'
    option force_link '1'
    option type 'bridge'
    option proto 'static'
    option ipaddr '192.168.1.1'
    option netmask '255.255.255.0'
    option ip6assign '64'

config interface 'wan'
    option ifname 'eth0'
    option proto 'dhcp'
    option hostname 'Raspberry_Pi'
    option peerdns '0'
    option dns '223.5.5.5 208.67.222.220 202.114.0.242'

config interface 'wan6'
    option ifname 'eth0'
    option proto 'dhcpv6'

结束

完成配置之后重启, 将wan口接在树莓派本身的网口上, 下级交换机/路由器接在USB无线网卡上就可以正常工作. 其他关于Openwrt的配置就自己发挥想象咯.
在树莓派上, 性能和存储容量基本上不是问题, 唯一的限制点就是IO带宽了.
如果要挂移动硬盘之类的, 请注意供电和速度, 或者直接上香蕉派/凌动工控主板就好了.


博客迁移工作


原本博客是挂在AwardSpace下的, 最初用的是免费套餐, 去年这个时候Basic促销只要$3一年就顺手入了.
现在Basic到期了, 续费的价格就比较感人了, 一年得$60.

正好一直都想入手一个VPS玩, 最近又查了一下发现了Bandwagonhost这家服务提供商, 最低级的套餐一年只要$19.
虽然只是单核, 256M RAM, 10G SSD和500G月流量, 但是像我这种日PV不会上10, 月PV不会上100的个人站点就随意了.
至于为什么不用Hexo这样的静态博客的话, 是因为想用PHP写点自己用的小服务什么的.
而且上了VPS的话, 那么SS的钱就可以省下来了, 而且也可以搭个VPN, 怎么看都觉得很棒.

怎么买这种事情就不说了, 可以银联, 支付宝和信用卡付款, 长时间有着5%off的优惠, 自己找找优惠码就好了.
有一点值得注意的是, 除了上述的通用套餐外, 还有为中国特别优化过链路的和性能配置好很多的另外两个套餐.
但是, 他们不能换机房, 也就是不能换ip. 万一以后被GFW吃了, 就GG. 以防万一, 还是入手了这个.

性能的话, 据说这家VPS是有很大的超售的.
SSH登录上去的感觉就是卡卡卡卡卡卡卡卡. 但是毕竟这么便宜, 要求也就不要太高了.
虽然SSH上去卡, 但是性能什么的感觉其实还行. 编译各种乱七八糟的组件也还挺快.
CPU是E3v5, 最大睿频4G. SSD RAID10的读写能够有900M/s左右.
网络速度, 我这边ping差不多是160+ms. 下载速度, 会从900+K/s慢慢涨到2M/s.
总而言之, 就是凑合用还是能行的, 要求别太高了. 毕竟便宜.

我用的博客系统是Typecho, 相比WordPress还是快不少, 原生支持MarkDown, 虽然不是太完美.
迁移主要分为两个部分, 一是从数据库导出数据. 另外一部分是下载文件.
数据库导出数据直接使用PHPMyAdmin就好了. 下载文件用FileZilla下载.
下载文件的时候就能够感受出来, 原来的主机商比新的VPS慢= =
毕竟欧洲还是没有美国西海岸近, 从网络拓扑上来说.

需要注意的就是, 修改config.inc.php里的数据库配置文件.
我在VPS安装的服务器是LNMP-1.3, 提供了很方便的脚本.
Nginx据说比Apache省内存, 适合像我这种内存比较紧张的情况.
对于Typecho而言, 默认安装, 在进管理员界面的时候会404.
需要修改/usr/local/nginx/conf/vhost下的站点配置文件
将include enable-php.conf -> include enable-php-pathinfo.conf
然后重启lnmp就可以了.

我在迁移中遇到的另外一个问题是, 数据库导入option表以后, HTTP 500内部服务器错误.
如果全新安装的话就不会有, 是正常的.
因为自己的文章不多, 外带想删掉以前的一些东西.
就干脆不要原来的数据了, 直接全新配置一遍.
以前的文章数据直接从导出的数据库文件里复制就好了.
只要把rn变成换行, 那么就和你在后台输入的内容是一致的.[Markdown大法好

顺带还尝试配置了一下IPSec Over L2TP, 但是好像内核并不支持IPSec...暂时就不折腾了吧


如何在Terminal中使用Sock5代理


大部分终端应用, 比如wget, curl都支持http_proxy, https_proxy变量配置HTTP代理.
然而常见的SS使用的则是SOCKS代理, 可以使用privoxy做SOCK->HTTP的转换.
但是相对而言privoxy比较重量级, 因此可以采用polipo做转换.

Mac OSX下可以使用brew安装:

brew install polipo

然后添加代理:

vi /usr/local/opt/polipo/homebrew.mxcl.polipo.plist

在array标签之间添加socksParentProxy选项:

<array>
        <string>/usr/local/opt/polipo/bin/polipo</string>
        <string>socksParentProxy=localhost:1080</string>
</array>

测试并启用代理

#!/bin/sh

export http_proxy=""
export https_proxy=""
curl ip.gs
launchctl unload /usr/local/opt/polipo/homebrew.mxcl.polipo.plist &> /dev/null
launchctl load /usr/local/opt/polipo/homebrew.mxcl.polipo.plist
ping -c 3 127.0.0.1 &> /dev/null
export http_proxy="localhost:8123"
export https_proxy="localhost:8123"
curl ip.gs

保存上述内容到http_proxy.sh文件, 需要代理时source文件既可.

source http_proxy.sh

Parallels Tools 11.0.0.3193 在Linux Kernel 4.2以上内核的修复


主要是参考这篇文章: http://journal.dedasys.com/2015/10/26/parallels-with-ubuntu-15-10/

首先你需要把kmods文件夹的压缩包用tar xvf prl_mod.tar.gz解包.
下面说一下需要修改的两个文件:
第一个文件是kmods/prl_tg/Toolgate/Guest/Linux/prl_tg/prltg.c
增加一个头文件的引用

#include "linux/vmalloc.h"

第二个文件是kmods/prl_fs/SharedFolders/Guest/Linux/prl_fs/inode.c在

-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
 #define compat_follow_link_t void*
 #else
 #define compat_follow_link_t int
 #endif

前新增

+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0)
+#define compat_follow_link_t const char*
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)

并删除

-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)

然后还需要将prlfs_follow_link这个函数做修改:
在函数前新增

+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0)
+static compat_follow_link_t prlfs_follow_link(struct dentry *dentry,
+ void **cookie)
+{
+ return *cookie = do_read_symlink(dentry);
+}
+#else

并在函数的结束点新增

+#endif

完成后使用tar czf打包回去就可以完成安装了.


利用crontabs的延时重试脚本


主要是有可能早上的时候电已经来了, 但是网络中心那边却还没有开放网络认证的许可, 导致路由器开机的时候认证失败.
同时由于路由新开机, 时间还未与网络同步所以单纯的设置crontabs并不能起到作用.
而且由于我希望自己可以在教学区域愉快地顶掉宿舍里路由器的认证, 所以也并不能启用mentohust本身超时重认证机制.
所以采取了开机后如果发现网络无法认证, 则读取当前系统时间再加一延时添加进crontabs的方法实现等待再认证.

#!/bin/sh

DELAY=30
STAR=$(echo \\*)
#MINUTES=$(date | awk \'{print $4}\' | sed \'s/\\([0-9]\\+\\):\\([0-9]\\+\\):\\([0-9]\\+\\)/\\2/\')
#HOURS=$(date | awk \'{print $4}\' | sed \'s/\\([0-9]\\+\\):\\([0-9]\\+\\):\\([0-9]\\+\\)/\\1/\')
MINUTES=$(date +\'%M\')
HOURS=$(date +\'%H\')
MINUTES=$(expr $MINUTES + $DELAY)
HOURS=$(expr $HOURS + 0)

if [ "$MINUTES" -gt 60 ]; then
    MINUTES=$(expr $MINUTES - 60)
    HOURS=$(expr $HOURS + 1)
fi

CMD="$MINUTES $HOURS $STAR $STAR $STAR /etc/init.d/mentohust_d >> /tmp/mentohust_d.log"
sed \'$d\' /etc/crontabs/root > /etc/crontabs/root.tmp
cp /etc/crontabs/root.tmp /etc/crontabs/root
rm /etc/crontabs/root.tmp
echo "$CMD" >> /etc/crontabs/root