Setup WPAD on EdgeRouter

Previously, I wrote Setup WPAD on Asus Merlin.

Similar on EdgeRouter.

1 Configure Domain name.

System

DHCP service

2 Prepare wpad.dat

I don’t have wpad.dat deployed on my router, but an internal Ubuntu server with nginx as httpd, IP 192.168.36.20.
wpad.dat is located to default server root, if you have your custom, make sure you have wpad.int.sskaje.name in your server_name directive.

/etc/nginx/site-enable/default

3 Configure Domain

I’ve moved all my dnsmasq configurations out of EdgeRouter’s configure mode, save under /config/etc and linked to /etc.

I added following line to any .conf under /etc/dnsmasq.d/

And restart dnsmasq

4 Configure DHCP Options

And my dhcp-server configure looks like

DO NOT try use-dnsmasq if you have a subnet with CIDR not in {8,16,24}.

Setup WPAD on EdgeRouter by @sskaje: https://sskaje.me/2016/11/setup-wpad-edgerouter/

基于SNIProxy的路由端网络流量定制分发方案

标题感觉很高大上,其实写得乱七八糟。

前序文章:
SNIProxy Bind Outgoing Interface
Build SNIProxy Debian Package for EdgeRouter
Ubnt EdgeRouter Lite 和 EdgeRouter X 上安装使用SNIProxy

不急,上边三篇可能会在本文内提及。

首先,sniproxy不解释了,但是如标题所属,sniproxy的版本不支持我要的功能,所以我就fork然后改了。
具体思路参考上述第一个链接。

接下来,直接进入正题。

按之前的玩法,我使用路由表来控制流量。这是一个很典型,也很正确的做法;但是也是一个很不好用的玩法。
参考文章:Set up OpenVPN Site-to-Site on UBNT EdgeRouter Lite, EdgeOS PPTP VPN客户端配置
PS:我维护了一份自己的路由表,地址在 https://ip.rst.im/blocks/sskaje

为了让定制化程度高一些,我配了一个Socks代理,实际上是在vpn对端配置的,本地路由做了个DNAT,转发过去了。这样我就可以用firefox+foxyproxy实现本地定制化规则。
参考文章:UBNT VPN + Socks5 代理Set up dante-server on Ubuntu

后来考虑到上述用起来麻烦,又趁着回老家的时候,在家里的ac68u merlin上实践了下WPAD,不过没有在自己家里的edgerouter上搞。
参考文章:Setup WPAD on Asus Merlin

此外,还试了一下基于源IP的firewall modify。印象中没单写blog,但是提过和用路由表的方案的优劣。
基本思路是:定义一个源地址的firewall network group;配置protocol static table;在LAN口的防火墙规则里增加modify,根据源地址组强行修改路由表。

从实际经验看,路由表不是最佳选择。
好处不必提,稳定,稳定,稳定。
坏处是,启动、更新慢慢慢。

而且现阶段,大量网站都用了诸如 cloudflare, amazon cloudfront,akamai,fastly之类的CDN服务,单纯按网段切路由,很不现实也很不灵活。
所以趁着需求,改造了一下sniproxy。
用的时间不长,所以暂时没法评估稳定性。

首先,软件部署在路由上。edgerouter lite 和 edgerouter x的包都打好了,1.9.0的固件可以直接装,下载地址在前边三个链接里有。

为了达到我要的目的,条件如下:
1 需要有本地DNS服务器(我的路由上有dnsmasq);
2 需要有稳定的VPN设备(我的是openvpn site2site,设备名vtun0)。
我的路由LAN IP是 192.168.32.1/24,设备eth0。

首先,为当前路由添加一个新的IP(我的是192.168.32.2/24),与默认IP同网段。
这里,命令行操作的时候务必别写错了设备名。其他没什么要注意的。
大致命令如下:

其次,配置好dnsmasq,将需要劫持的域名解析到 192.168.32.2。解析的配置参考下列例子

实际的经验是,不要用 set service dns forwarding options 来设置dnsmasq,自己维护一个配置文件,放在 /config/ 下,link/etc/dnsmasq.d

第三步,安装配置我的版本的sniproxy,假定监听端口分别问 192.168.32.2:3080 和 192.168.32.2:3443,分别用于接收 80端口和443端口的请求。
安装步骤参考最前边的链接。
配置文件参考

最后,配置DNAT,将192.168.32.2:80和192.168.32.2:443分别转到3080和3443,防止80和443的请求到达路由的lighttpd。

基于SNIProxy的路由端网络流量定制分发方案 by @sskaje: https://sskaje.me/2016/11/%e5%9f%ba%e4%ba%8esniproxy%e7%9a%84%e8%b7%af%e7%94%b1%e7%ab%af%e7%bd%91%e7%bb%9c%e6%b5%81%e9%87%8f%e5%ae%9a%e5%88%b6%e5%88%86%e5%8f%91%e6%96%b9%e6%a1%88/

SNIProxy Bind Outgoing Interface

这篇纯技术,没兴趣的别看。

关于需求

最早试图用路由器自带的功能去实现sni检测+自动路由,结果发现edgerouter的dpi没开放太多资料。
再又试图用squid去实现正向代理,绑定上行网络地址或者设备,虽然edgerouter自带squid以实现transparent proxy,但是自带版本SNI检测不支持(新版不知),绑定upstream的地址或者设备也没看到有人说支持。
又考虑过haproxy,但是这个必须自己写backend(似乎可以haproxy + squid,没去实践过,至少haproxy的acl要写好长;而且这个组合里haproxy都可以直接被跳过,反正有DNAT也有DNS劫持)。

从上边的方案思考过程,我觉得应该能看懂我想要什么。

关于实现

选用sniproxy,也算偶然。虽然之前vps上实验sni检测+代理的时候,大概看了眼(但是最后还是选了haproxy)。不过最后选这个的重要原因就是好改 XD
官方github在https://github.com/dlundquist/sniproxy。

先考虑的方案是,通过socket上联时绑定客户端IP。
本身支持上行设置请求的源地址,大致实现代码在 connection.c:

但是经过试验,配置source address后,数据包还是会根据路由上的路由表跳到域名解析IP该走的那个网络。

所以,这个方案是不满足我的要求的。

如果绑定IP不行,那就试试绑定设备。
绑定IP的方案的可行性,很早以前跟同学Windows下讨论一个客户端设计的时候验证过;但是绑定设备的,完全没搞过。
现查。

然后查到了 SO_BINDTODEVICE

SO_BINDTODEVICE
Bind this socket to a particular device like “eth0”, as specified in the passed interface name. If the name is an empty string or the option length is zero, the socket device binding is removed. The passed option is a variable-length null-terminated interface name string with the maximum size of IFNAMSIZ. If a socket is bound to an interface, only packets received from that particular interface are processed by the socket. Note that this only works for some socket types, particularly AF_INET sockets. It is not supported for packet sockets (use normal bind(2) there).
Before Linux 3.8, this socket option could be set, but could not retrieved with getsockopt(2). Since Linux 3.8, it is readable. The optlen argument should contain the buffer size available to receive the device name and is recommended to be IFNAMSZ bytes. The real device name length is reported back in the optlen argument.

不过比较麻烦的是,这个只支持IPV4,而且必须使用root。

具体实践在 https://github.com/sskaje/sniproxy
mips(64)/mipsel的deb包已经放在 http://dl.sskaje.me/debian/,供 edgerouter lite/edgerouter x使用,未签名。

具体代码:

还需要说明的是,这个也只能在Linux上用。

关于应用

应用方案,单独写,跟这篇关系没那么大。

SNIProxy Bind Outgoing Interface by @sskaje: https://sskaje.me/2016/11/sniproxy-bind-outgoing-interface/

Build SNIProxy Debian Package for EdgeRouter

SNIProxy的最新版0.4.0,上一次提交已经很久以前了,建议直接使用github库里的代码。
官方github:https://github.com/dlundquist/sniproxy
我的fork:https://github.com/sskaje/sniproxy

前文所说,Debian Wheezy已经LTS了,所以从依赖开始。

不过,我没有去配交叉编译的环境,而是直接qemu装了两个虚拟机,一个mips(给EdgeRouter Lite),一个mipsel(给EdgeRouter X),具体方法可以参考之前的blog:Install Debian MIPS and Debian PowerPC on OSX

好处是,闭着眼睛就可以配构件环境;坏处是,慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢慢到死了。

以mips为例,mipsel一模一样。

构件环境不说了。

先编译 libudns。

udns的官方包里没有debian的打包配置,所以我直接从debian官方包列表的链接里下载,下载地址在:https://packages.debian.org/source/sid/udns
三个文件都下,用到的是两个tarball。

按上述命令执行完之后,deb包会出现在上一级目录,生成的文件包括:

  • libudns0_0.4-1_mips.deb
  • libudns-dev_0.4-1_mips.deb
  • udns-utils_0.4-1_mips.deb
  • udns_0.4-1_mips.changes

其中,libudns-dev_0.4-1_mips.deb 直接安装在开发环境,libudns0_0.4-1_mips.deb 装在路由上。

然后编译sniproxy
git clone 之后,同样进目录执行

Build SNIProxy Debian Package for EdgeRouter by @sskaje: https://sskaje.me/2016/11/build-sniproxy-debian-package-edgerouter/

Ubnt EdgeRouter Lite 和 EdgeRouter X 上安装使用SNIProxy

EdgerRouter Lite和EdgerRouter X使用的固件版本 1.9.0 是基于debian wheezy的,但是debian wheezy现在已经进入LTS了,mips和mipsel不在官方的维护架构里,以至于现在无法使用官方的apt更新debian-security,而且在ubnt的路由上,安装很多开发库都没法搞了。

EdgerRoute Lite 使用的是mips64,debian源里需要用 mips 的包;而 EdgeRoute X 使用的是mipsel。
使用lscpu看CPU的信息:

EdgeRouter Lite

EdgeRouter X

准备

编译libudns和sniproxy

待补充。我已经把构建好的包发到了 http://dl.sskaje.me/debian/

SSH登录ER

下载软件

EdgeRouter Lite 请使用mips

EdgeRouter X 请使用mipsel

安装

配置

请参考官方文档。
按我的需求,官方的功能没法满足,所以我对官方的源码做了一些改动,具体可见 https://github.com/sskaje/sniproxy

使用

首先修改 /etc/default/sniproxy,这样才可以使用init的脚本启动

启动

Ubnt EdgeRouter Lite 和 EdgeRouter X 上安装使用SNIProxy by @sskaje: https://sskaje.me/2016/11/install-sniproxy-ubnt-edgerouter-lite-edgerouter/