DHCP分配不同的网关地址给客户端

基础网络环境是这样:
1.一台ROS负责ADSL拨号上网,IP地址是:192.168.1.1
2.一台LEDE负责爱国上网,IP地址是:192.168.1.2,实际上LEDE还是通过ROS上网的,只是增加了爱国上网的功能(因为ROS功能比较单一,没有这个功能)

需求是:
1.局域网中的默认机器都能通过DHCP自动获取到IP地址,并访问我大中华局域网,网关是ROS;
2.少数几台机器可以自动获取到网关为LEDE,访问一些不存在的网站,比如油管。

为什么不把所有的机器网关都设置成LEDE?
1.因为LEDE转发效率没有ROS高,迅雷下载的时候CPU占用率飙升;
2.既然所有的流量实际上最后都要从ROS出去,对那些不需要爱国上网的客户端来说,直接把ROS作为网关肯定效率最高。

以上

最开始是想在ROS上实现需求,后来发现ROS的DHCP服务器实现不了(或者是我没找到办法)
经过对LEDE自带的dnsmasq研究了一番,实现了需求。

实现过程:
1.在ROS上关闭DHCP服务器,LEDE上开启DHCP,给局域网内的机器分配IP地址;
2.编辑LEDE上/etc/dnsmasq.conf的内容,增加以下这段:

log-dhcp
dhcp-option=option:dns-server,192.168.1.2 #设置默认的DNS服务器为192.168.1.2
dhcp-option=option:router,192.168.1.1 #设置默认的网关为192.168.1.1
dhcp-option=tag:xLEDE,option:router,192.168.1.2 #标记tag为xLEDE的网关为192.168.1.2

dhcp-host=a8:a6:13:5c:af:29,192.168.1.53,TV #假设电视的MAC地址是:a8:a6:13:5c:af:29,它自动获取到的IP地址是192.168.1.53,网关是默认的192.168.1.1
dhcp-host=ac:c3:ee:f7:17:35,set:xLEDE,192.168.1.54,Xiaomi #小米手机MAC地址ac:c3:ee:f7:17:35,获取到的IP地址是192.168.1.54,设置标记为xLEDE,网关是192.168.1.2

完。

使用uci命令行读取uci config小结

UCI是一个用C语言编写的小应用程序,用来集中管理OpenWrt/LEDE的所有配置选项,UCI配置文件位于目录 /etc/config/内。

假设有以下配置文件:/etc/config/v2conf,内容如下:

#这里是注释,实际使用中请删除
#每个config就是一个段落
config v2conf ‘v2name’ #段落类型是v2conf,段落名字是v2name,该段落在uci show中显示为v2conf.v2name
option enabled ‘1’ #在uci show中显示为v2conf.v2name.enabled=’1′
option server ‘s07030093’ #也可以直接读取uci get v2conf.v2name.server,

config subscriptions #这个段落是匿名的,段落类型是subscriptions,无段落名,该匿名段落在uci show中显示为v2conf.@subscriptions[0]
option address ‘http://www.baidu.com/’

config subscriptions #这个段落也是匿名的,该匿名段落在uci show中显示为v2conf.@subscriptions[1]
option address ‘http://www.google.com/’

config servers ‘server1’ #有段落名字就好读取了,uci show v2conf.server1
option name ‘name1′
option success ’62’
option total ‘129’
option uptime ‘2019-04-21 21:04:56’
#uci get v2conf.server1.uptime
#返回2019-04-21 21:04:56

config servers ‘s07030093’
option name ‘name2′
option success ’36’
option total ‘165’
option uptime ‘2019-04-21 21:25:02’

config servers ‘s61355758’
option name ‘name3’
option success ‘7’
option total ’33’
option uptime ‘2019-04-21 20:56:49′

uci命令可以直接在OpenWrt/LEDE的命令行中使用,如在控制台中输入:uci show v2conf
将显示如下内容:
v2conf.v2name=v2conf
v2conf.v2name.enabled=’1′
v2conf.v2name.server=’s07030093′
v2conf.@subscriptions[0]=subscriptions
v2conf.@subscriptions[0].address=’http://www.baidu.com/’
v2conf.@subscriptions[1]=subscriptions
v2conf.@subscriptions[1].address=’http://www.google.com/’
v2conf.server1=servers
v2conf.server1.name=’name1′
v2conf.server1.success=’62’
v2conf.server1.total=’129′
v2conf.server1.uptime=’2019-04-21 21:04:56′
v2conf.s07030093=servers
v2conf.s07030093.name=’name2′
v2conf.s07030093.success=’36’
v2conf.s07030093.total=’165′
v2conf.s07030093.uptime=’2019-04-21 21:25:02′
v2conf.s61355758=servers
v2conf.s61355758.name=’name3′
v2conf.s61355758.success=’7′
v2conf.s61355758.total=’33’
v2conf.s61355758.uptime=’2019-04-21 20:56:49′

常用uci命令:
1.uci show
用法:uci show config #显示config配置文件的所有配置
示例:
uci show v2conf #显示/etc/config/v2conf配置文件的所有配置
uci show v2conf.v2name #只显示v2conf.v2name段落

2.uci get
用法:uci get config.section.option #获取某option具体的值
示例:
uci get v2conf.v2name.enabled #获取enabled的值
uci get v2conf.v2name #如果只get到段落名,获取的是段落类型v2conf

3.uci set
用法:uci set config.section.option=value #设置某option具体的值为value
示例:
uci set v2conf.v2name.enabled=0
然后uci get v2conf.v2name.enabled 发现返回值是0

4.uci delete
4.1用法:uci delete config.section.option #删除某option
示例:
uci delete v2conf.s61355758.uptime
然后uci show v2conf.s61355758返回
v2conf.s61355758=servers
v2conf.s61355758.name=’name3′
v2conf.s61355758.success=’7′
v2conf.s61355758.total=’33’
发现uptime已删除

4.2用法:uci delete config.section #删除某段落section
示例:
uci delete v2conf.s61355758
然后uci show v2conf.s61355758返回
uci: Entry not found
段落不存在

5.uci commit
用法:uci commit config #提交修改。因为之前经过uci set/delete的值实际上都还在缓存内,重启以后就会丢失
示例:
uci commit v2conf

v2设置透明代理的要点

所谓透明代理就是局域网的流量直接通过网关,局域网内的客户端(电脑或者智能终端等)不需要再进行单独的代理设置。在网关上根据域名或者IP地址匹配,到底是走国内还是国外。这个过程对于客户端来说是完全透明的。

要点:
0. 在v2.json上存在配置
“inbounds”: [
{
“protocol”: “dokodemo-door”, #任意门协议,实现透明代理
“port”: 1234, #从1234端口进来的直接转发
“settings”: {
“network”: “tcp,udp”,
“followRedirect”: true
},
“sniffing”: {
“enabled”: false,
“destOverride”: [
“http”,
“tls”
]
}
}
]

1.在v2.json配置文件上,outbounds增加如下段落:
{
“sendThrough”: “0.0.0.0”,
“protocol”: “freedom”,
“settings”: { },
“tag”: “direct”, #针对tag为direct进行处理
“streamSettings”: {
“sockopt”: {“mark”: 255} #做标记,从防火墙上直连
}
}

2.在v2.json配置文件上,增加如下段落routing:
“routing”: {
“domainStrategy”: “IPIfNonMatch”, #当域名没有匹配任何规则时,将域名解析成IP(A 记录或AAAA 记录)再次进行匹配
“rules”: [
{
“type”: “field”,
“outboundTag”: “direct”,
“domain”: [“geosite:cn”] #如果是国内的域名匹配outbound中的direct标记
},
{
“type”: “field”,
“outboundTag”: “direct”,
“ip”:[“geoip:cn”] #如果是国内的IP匹配outbound中的direct标记
},
{
“type”: “field”,
“outboundTag”: “direct”,
“ip”:[“geoip:private”] #如果是私有IP匹配outbound中的direct标记
}
]
}

3.在iptables防火墙增加以下规则:
iptables -t nat -N V2RAY
iptables -t nat -A V2RAY -d x.x.x.x -j RETURN #x.x.x.x是v2服务器的IP,所有到服务器的流量直连
iptables -t nat -A V2RAY -d 0.0.0.0/8 -j RETURN #局域网、特殊IP直连
iptables -t nat -A V2RAY -d 10.0.0.0/8 -j RETURN #局域网、特殊IP直连
iptables -t nat -A V2RAY -d 127.0.0.0/8 -j RETURN #局域网、特殊IP直连
iptables -t nat -A V2RAY -d 169.254.0.0/16 -j RETURN #局域网、特殊IP直连
iptables -t nat -A V2RAY -d 172.16.0.0/12 -j RETURN #局域网、特殊IP直连
iptables -t nat -A V2RAY -d 192.168.0.0/16 -j RETURN #局域网、特殊IP直连
iptables -t nat -A V2RAY -d 224.0.0.0/4 -j RETURN #局域网、特殊IP直连
iptables -t nat -A V2RAY -d 240.0.0.0/4 -j RETURN #局域网、特殊IP直连
iptables -t nat -A V2RAY -p tcp -j RETURN -m mark –mark 0xff #0xff就是255,所有标记为255的流量直连,这样就跟刚才v2的outbounds标记对应上了
iptables -t nat -A V2RAY -p tcp -j REDIRECT –to-ports 1234 #其他的流量都转发到1234端口,这里的1234是inbounds段落中定义的转发端口
iptables -t nat -A PREROUTING -p tcp -j V2RAY

如何在openWRT/LEDE固件中添加第三方二进制IPK?

所谓的第三方二进制ipk就是没有源码,只有ipk文件。

主要参考文档:
OpenWrt Project: 使用镜像生成工具 (Image Builder)
https://openwrt.org/start?id=zh/docs/guide-user/additional-software/imagebuilder

编译环境及步骤参见:
编译openWRT/LEDE固件 http://xingyuncheng.net/?p=19

有两种办法:
1.从源码编译
1.1 上传
将需要添加的ipk文件上传到~/lede/bin/packages/x86_64/packages/packages/目录;

1.2 创建索引
上传ipk文件以后,需要将所上传的ipk文件进行索引,不然编译程序不认识,没法编译进固件。

#先设置PATH路径,否则创建过程会提示mkhash出错
export PATH=”~/lede/staging_dir/host/bin:$PATH”

cd ~/lede/bin/packages/x86_64/packages/packages/
~/lede/scripts/ipkg-make-index.sh ./ > ./Packages
gzip -9c ./Packages > ./Packages.gz

很不幸,运行的时候出现错误提示:
tar: ./control.tar.gz: Not found in archive
tar: Exiting with failure status due to previous errors

ipk文件其实就是压缩文件打包,只要将.ipk改成.tar.gz后缀,再解压缩就能看到ipk文件内容。
看了一下我要编译的ipk文件结构跟正常的不同,压缩包内显示的不是./control.tar.gz,而是control.tar.gz,所以没办法只好把~/lede/scripts/ipkg-make-index.sh修改了一下,24行内:
tar -xzOf $pkg ./control.tar.gz
改成:
tar -xzOf $pkg control.tar.gz
保存以后重新运行:
~/lede/scripts/ipkg-make-index.sh ./ > ./Packages
成功。

然后再运行
gzip -9c ./Packages > ./Packages.gz

这样~/lede/bin/packages/x86_64/packages/packages/文件夹就多了2个文件
Packages
Packages.gz

1.3 然后按照正常流程编译固件
编译完成以后,在固件的/根目录就会有上传的ipk文件。
但不幸的是,这样上传的ipk文件并不能自动安装,还需要自己手工安装一下。
不完美。

2.
用imagebuilder添加进去(可以自动安装进固件)
imagebuilder是从源码编译的时候,一个可选的中间文件,具体生成办法请百度。

2.1 上传ipk
~/imagebuilder/packages/是原生ipk所在路径,不要将第三方ipk放在同一个目录下。
所以上传到以下位置:~/imagebuilder/packages/packages/

2.2 创建索引文件
export PATH=”~/imagebuilder/staging_dir/host/bin:$PATH”
cd ~/imagebuilder/packages/packages/
~/imagebuilder/scripts/ipkg-make-index.sh ./ > ./Packages
gzip -9c ./Packages > ./Packages.gz

中间ipkg-make-index.sh运行出错也是参照1.2步骤修改的。
创建好的索引位于以下绝对路径:
/home/oldfox126/imagebuilder/packages/packages/Packages.gz
oldfox126是我登录Ubuntu的用户名

2.3 修改软件源
vi ~/imagebuilder/repositories.conf
在这行
# src custom file:///usr/src/openwrt/bin/x86/packages
后面增加一行:
src custom file:///home/oldfox126/imagebuilder/packages/packages
这里的oldfox126要修改成你登录Ubuntu的用户名
保存。

2.4 编译固件包
cd ~/imagebuilder/
make image PACKAGES=”smartdns luci-app-smartdns”

这里的smartdns、luci-app-smartdns,是我刚才上传的2个第三方二进制ipk,只要包名字不需要版本号和日期。如果不清楚包名字叫什么,
cat ~/imagebuilder/packages/packages/Packages
就看到了。

这样增加的ipk,才会自动安装进固件。
完美!

编译openWRT/LEDE固件

最近一个星期反复尝试编译openwrt/LEDE固件,期间失败很多次,只成功了几次,感觉快成玄学了:)
关键是编译速度非常慢,以小时记,1-3小时是起步。
当你睡了一觉起来,发现编译失败,那酸爽,不敢想象……

目前成功编译的代码如下:
sudo apt-get update
sudo apt-get -y install build-essential asciidoc binutils bzip2 gawk gettext git libncurses5-dev libz-dev patch unzip zlib1g-dev lib32gcc1 libc6-dev-i386 subversion flex uglifyjs git-core gcc-multilib p7zip p7zip-full msmtp libssl-dev texinfo libglib2.0-dev xmlto qemu-utils upx

git clone https://github.com/coolsnowwolf/lede
cd lede
./scripts/feeds update -a
./scripts/feeds install -a

make menuconfig
make download
make -j1 V=s TARGET_DEVICES=x86

再记录一下踩过的坑:
1.首先我使用的是:Ubuntu 14 LTS x64,还没测试过其他的版本,不知道高版本的Ubuntu是不是更容易成功编译;
2.划重点,******内存一定要在4G以上******;
3.划重点,在编译过程中会下载很多文件,基本都要翻墙下载而且网络很不稳定,所以在最后一步:
make -j1 V=s TARGET_DEVICES=x86
之前有一个预先下载的动作:
make download
但就算预先下载了也不能保证下载回来的文件都是正确的,最好在make download以后查一下
lede/dl/目录,按照文件大小排序。如果有文件只有几个字节,那肯定不对,直接删掉该文件,然后重新:make download

LEDE安装SmartDNS

wget -c https://downloads.openwrt.org/releases/18.06.2/packages/x86_64/base/libopenssl_1.0.2q-1_x86_64.ipk
wget -c https://github.com/pymumu/smartdns/releases/download/Release23/luci-app-smartdns.1.2019.04.02-0832.all.ipk
wget -c https://github.com/pymumu/smartdns/releases/download/Release23/smartdns.1.2019.04.02-0832.x86_64.ipk

opkg update
opkg install ./libopenssl_1.0.2q-1_x86_64.ipk
opkg install ./smartdns.1.2019.04.02-0832.x86_64.ipk
opkg install ./luci-app-smartdns.1.2019.04.02-0832.all.ipk