RouterOS上的电信/移动双路由,按目标IP确定出口
本帖最后由 stevemorrislian 于 2019-3-15 17:02 编辑基本设想是国外用移动线路优先,电信用电信出口优先,其他就随缘了
首先是下载2个路由表,一个国内IP地址表,一个电信地址表=>这里的关键是逻辑关系,想清楚与和非的关系,因为出口列表很难用两个 《非》来界定出口方向
GitHub的ChnRoutes路由表,以APNIC的独立系统号为标准,随时更新的
https://github.com/fivesheep/chnroutes/blob/master/chnroutes.py
是用python编写的,也可以直接下载读取的txt文件。或者rsc执行文件,可以放到ROS下去执行
在路由器中建立地址表Domestic,用ip->firewall->address list以后也可以添加这个表
IP -> routes下,修改0.0.0.0/0的移动出口网关,添加Routing Mark=CM
dst-address=0.0.0.0/0 gateway=192.168.100.1 gateway-status=192.168.100.1 reachable viapppoe-out1
distance=1 scope=30 target-scope=10 routing-mark=CM
也就是说这个标签的会走192.168.100.1这个出口。
然后在IP->firewall->mangle下,建立prerouting的chain,在advance下设置条件dest. address list为"非"Domestic,方框的"!“表示非,domestic是下载的地址表
chain=prerouting action=mark-routing new-routing-mark=CM passthrough=yesdst-address-list=!Domestic
其中prerouting的数据链表示在路由前作标记,这样不在Domestic的表中的目标IP,就打了标记CM,路由将选择移动出口
但是国内除了电信,还有联通。而去联通目标也是移动更好。
所以第二选择是电信,方法差不多,就是电信的标记TeleCom,目标地址不用非,也就是没“!”号。
如果有第三,第四出口,都不能用!的地址表
最后还是把不打标记的路由0.0.0.0/0加上,免得数据出不去,实际上考虑的是3出口状态,你懂的!
在nat的配置下,每个方向都要做masquerade,看上去差不多了。考虑到电信,移动的MTU,MSS不同change mss,取最小的值。虽然估计1480也够
chain=forward action=change-mss new-mss=1460 passthrough=yes tcp-flags=syn protocol=tcp log=no log-prefix=""
后面讲我自己遇到的问题
1,原来想只打telecom的标记,因为打标记的路由是优先的,如果打电信路由,国外的就没有标记,想出国的数据就会走到国内(是的。逻辑混乱,但请另外理解),最后没有标记的还是会经过移动出口的
2,想先打移动(移动不肯给公网IP,固定的私网)而不是电信,发现用非电信+非国内打标记,那么国内的标记就会出现2次都打标记的情况(国外也是非电信,与逻辑混乱一个意义),对路由器而言会占用CPU,关键是还会走错地方
3,手贱,选择了自己路由器PPPoE的电信出口,这样就有一个公网IP可以测试用途了(比如voip的电话通过l2tp用来从家里打电话)。这引起了LOG大爆发,赶紧开防火墙
规则:
0 chain=input action=drop src-address-list=BlockIPs log=no log-prefix=""
1 chain=forward action=drop src-address-list=BlockIPs log=no log-prefix=""
2 chain=output action=drop dst-address-list=BlockIPs log=no log-prefix=""
建立黑名单,进出遇到BlockIPs表里的IP地址全部封杀,用mangle,因为黑客也是不固定IP的,就停掉5天,免得地址表太大
chain=input action=add-src-to-address-list protocol=tcp src-address=!172.16.0.0/16 src-address-list=192.168.0.0/16address-list=BlockIPs address-list-timeout=5d port=21-25 log=no log-prefix=""
原来只想input的可能,发现log内还有很多port=23的试探,加了prerouting,
chain=prerouting action=add-src-to-address-list protocol=tcp src-address=!192.168.0.0/16src-address-list=!172.16.0.0/16 address-list=BlockIPs address-list-timeout=5d port=21-25 log=no log-prefix=""
对voip盗打电话我比较痛恨,关15天,地址表里也分得清情况
chain=prerouting action=add-src-to-address-list protocol=udp src-address=!192.168.0.0/16src-address-list=!172.16.0.0/16 address-list=BlockIPs address-list-timeout=2w1d port=5060-5061 log=no log-prefix=""
三天有680个IP被加入BlockIPs,其中1/10来自盗打电话的试探。以后看connections再加规则
4,一个动态路由的测试,为了保障移动出口到国外的带宽,大部分还是走电信出口,但遇到特殊需求时走移动口
开了一个192.168.88.0/24的DHCP,这个地址段中如果访问推文(或者开着这个窗口不关),以后所有数据就去移动,平常即使国外也走电信出口
先建立钩子,一旦访问目标在ToWatch这个List里,就把源IP放进去国外的临时表SourceTemp(过期时间1分钟),这个list内就是自己常看的电视,比如skynet,Bloomberg,twitter这些IP
chain=prerouting action=add-src-to-address-list protocol=tcp src-address=192.168.88.0/24dst-address-list=ToWatch address-list=SourceTemp address-list-timeout=1m log=no log-prefix=""
然后给源SourceTemp也打上第一个CM的标记就可以了,只要关掉相应的窗口,就回到最后不打标记的出口
5,路由器上同时做dns forward,这样路由器本身就要访问外网,并没有内网192.168.0.0/16作为源地址的连接。为了解决这个问题,另外建立chain=output,条件一样
同时又发现又有大量的dns访问,同样用mangle的input链,从PPPoE进来的外网IP都放入黑名单。
发现不能把forward的上线dns设置为8.8.8.8,因为它太著名,许多污染记录都是针对它,不如找个冷门的dns,只要不在国内,也不通过国内的接口去访问
6,终于找到了解决DNS的方法,不仅要躲在防火墙后,lookup也不能从正常的出口走。好在我本来就通过CAPsMAN管理着多个LAP,用LAP同步8.8.8.8
7,有些用了CDN的网站,被分流后无法正常访问,因为它本身就用了不同的IP,当来源属于不同的IP时就无法正常运作了。我看股票的网站就有这情况,解决方法就是先建立一个表,CDNSites,一旦访问这些IP,就把源IP加入NoCDN,对NoCDN的源暂时(30秒)不走打标记的路由。一旦手机把APP关掉,就恢复按目标IP分流,方法基本同4,只是反着来。
本帖最后由 stevemorrislian 于 2018-10-15 22:07 编辑
168kingmu 发表于 2018-10-14 22:57
楼主实现了嘛?我和楼主一模一样,加一个QQ交流一下
我的dns解析次序是自己本地服务器的dnsmasq,然后是114.114.114.114,所以结果大多不是电信的,目标移动的最多。这是对sina的结果
/tool> traceroute www.sina.com
# ADDRESS LOSS SENT LAST AVG BEST WORST STD-DEV STATUS
1 172.16.6.1 0% 2 4.3ms 4.5 4.3 4.7 0.2
2 ########## 0% 298.4ms 87.4 76.3 98.4 11.1
3########### 0% 2 5.7ms 6 5.7 6.2 0.3
4 172.18.27.1 0% 240.4ms 42.4 40.4 44.3 2
5 223.119.0.165 0% 241.9ms 41.6 41.3 41.9 0.3
6 223.118.18.161 0% 2 245.5ms 245 244.4 245.5 0.6
7 149.14.81.185 0% 2 256.1ms 263.3 256.1 270.5 7.2
8 130.117.2.13 0% 2 264.4ms 264.4 264.4 264.4 0
9 154.54.56.238 0% 1 266.8ms 266.8 266.8 266.8 0
10 100% 1 timeout
11 100% 1 timeout
12 100% 1 timeout
13 100% 1 timeout
14 100% 1 timeout
/tool> traceroute www.sina.com.cn
# ADDRESS LOSS SENT LAST AVG BEST WORST STD-DEV STATUS
1 192.168.100.1 0% 4 0.2ms 1.2 0.2 4.1 1.7
2 100.75.0.1 0% 4 7.3ms 7.8 7 8.9 0.7
3 ######### 0% 4 7ms 13.4 5.8 33.2 11.4
4************* 25% 4 47ms 22 7.6 47 17.7
5########## 0% 4 7ms 7.2 7 7.3 0.1
6 100% 4 timeout
7 221.183.55.33 50% 4 timeout 10.3 9.9 10.6 0.4
8 223.120.22.6 0% 458.9ms 59.4 58.9 60.3 0.7
9 223.120.2.1 0% 340.1ms 40 39.9 40.1 0.1
10 223.120.2.54 0% 3 40ms 41.2 40 42 0.9
11 123.255.90.36 0% 341.2ms 42.2 41.2 43.7 1.1
12 218.189.124.194 0% 351.6ms 49.8 48.6 51.6 1.3
13 100% 3 timeout
14 36.51.254.37 0% 341.9ms 42.3 41.9 43.1 0.5
> server 202.96.209.133
默认服务器:ns-pd.online.sh.cn
Address:202.96.209.133
> www.sina.com.cn
服务器:ns-pd.online.sh.cn
Address:202.96.209.133
非权威应答:
名称: spool.grid.sinaedge.com
Address:202.102.94.124
Aliases:www.sina.com.cn
>
/tool> traceroute 202.102.94.124
# ADDRESS LOSS SENT LAST AVG BEST WORST STD-DEV STATUS
1 ########## 0% 12 3.9ms 4.9 1.9 7.2 1.8
2 ########## 0% 12 4.7ms 6.6 3.1 10.7 2.2
3 ########## 0% 12 3.4ms 4.3 3 9.4 2.2
4 202.97.29.110 0% 12 8.9ms 8.6 7.4 10.7 0.8
5 61.160.140.46 0% 12 8.2ms 7.7 6.8 8.2 0.4
6 202.102.73.194 0% 1211.4ms 14.3 11.4 25.6 3.7
7 180.97.12.62 0% 1213.5ms 27.4 11.5 60.2 15.5
8 100% 12 timeout
9 202.102.94.124 0% 11 7.8ms 7.9 7.6 8.2 0.2 本帖最后由 stevemorrislian 于 2018-10-21 12:46 编辑
做了点修改,产生的是适合ROS用的,最后一列是时间,可以用excel之类的表格软件排序,这样可以添加到原来的list中
#!/usr/bin/env python
import re
import urllib2
import sys
import argparse
import math
import textwrap
def generate_ovirtual**(metric):
results = fetch_ip_data()
rfile=open('routes.txt','w')
for ip,datenum,mask2 in results:
route_item="add list=domesticList address=%s/%s \t %s \n"%(ip,mask2,datenum)
rfile.write(route_item)
rfile.close()
print "Usage: Append the content of the newly created routes.txt to your openvirtual** config file," \
" and also add 'max-routes %d', which takes a line, to the head of the file." % (len(results)+20)
def generate_linux(metric):
results = fetch_ip_data()
upscript_header=textwrap.dedent("""\
#!/bin/bash
export PATH="/bin:/sbin:/usr/sbin:/usr/bin"
OLDGW=`ip route show | grep '^default' | sed -e 's/default via \\([^ ]*\\).*/\\1/'`
if [ $OLDGW == '' ]; then
exit 0
fi
if [ ! -e /tmp/virtual**_oldgw ]; then
echo $OLDGW > /tmp/virtual**_oldgw
fi
""")
downscript_header=textwrap.dedent("""\
#!/bin/bash
export PATH="/bin:/sbin:/usr/sbin:/usr/bin"
OLDGW=`cat /tmp/virtual**_oldgw`
""")
upfile=open('ip-pre-up','w')
downfile=open('ip-down','w')
upfile.write(upscript_header)
upfile.write('\n')
downfile.write(downscript_header)
downfile.write('\n')
for ip,mask,_ in results:
upfile.write('route add -net %s netmask %s gw $OLDGW\n'%(ip,mask))
downfile.write('route del -net %s netmask %s\n'%(ip,mask))
downfile.write('rm /tmp/virtual**_oldgw\n')
print "For p p t p only, please copy the file ip-pre-up to the folder/etc/ppp," \
"and copy the file ip-down to the folder /etc/ppp/ip-down.d."
def generate_mac(metric):
results=fetch_ip_data()
upscript_header=textwrap.dedent("""\
#!/bin/sh
export PATH="/bin:/sbin:/usr/sbin:/usr/bin"
OLDGW=`netstat -nr | grep '^default' | grep -v 'ppp' | sed 's/default *\\(*\\) .*/\\1/' | awk '{if($1){print $1}}'`
if [ ! -e /tmp/p p t p_oldgw ]; then
echo "${OLDGW}" > /tmp/p p t p_oldgw
fi
dscacheutil -flushcache
route add 10.0.0.0/8 "${OLDGW}"
route add 172.16.0.0/12 "${OLDGW}"
route add 192.168.0.0/16 "${OLDGW}"
""")
downscript_header=textwrap.dedent("""\
#!/bin/sh
export PATH="/bin:/sbin:/usr/sbin:/usr/bin"
if [ ! -e /tmp/p p t p_oldgw ]; then
exit 0
fi
ODLGW=`cat /tmp/p p t p_oldgw`
route delete 10.0.0.0/8 "${OLDGW}"
route delete 172.16.0.0/12 "${OLDGW}"
route delete 192.168.0.0/16 "${OLDGW}"
""")
upfile=open('ip-up','w')
downfile=open('ip-down','w')
upfile.write(upscript_header)
upfile.write('\n')
downfile.write(downscript_header)
downfile.write('\n')
for ip,_,mask in results:
upfile.write('route add %s/%s "${OLDGW}"\n'%(ip,mask))
downfile.write('route delete %s/%s ${OLDGW}\n'%(ip,mask))
downfile.write('\n\nrm /tmp/p p t p_oldgw\n')
upfile.close()
downfile.close()
print "For p p t p on mac only, please copy ip-up and ip-down to the /etc/ppp folder," \
"don't forget to make them executable with the chmod command."
def generate_win(metric):
results = fetch_ip_data()
upscript_header=textwrap.dedent("""@ECHO off
for /F "tokens=3" %%* in ('route print ^| findstr "\\<0.0.0.0\\>"') do set "gw=%%*"
""")
upfile=open('virtual**up.bat','w')
downfile=open('virtual**down.bat','w')
upfile.write(upscript_header)
upfile.write('\n')
upfile.write('ipconfig /flushdns\n\n')
downfile.write("@echo off")
downfile.write('\n')
for ip,mask,_ in results:
upfile.write('route add %s mask %s %s metric %d\n'%(ip,mask,"%gw%",metric))
downfile.write('route delete %s\n'%(ip))
upfile.close()
downfile.close()
# up_vbs_wrapper=open('virtual**up.vbs','w')
# up_vbs_wrapper.write('Set objShell = CreateObject("Wscript.shell")\ncall objShell.Run("virtual**up.bat",0,FALSE)')
# up_vbs_wrapper.close()
# down_vbs_wrapper=open('virtual**down.vbs','w')
# down_vbs_wrapper.write('Set objShell = CreateObject("Wscript.shell")\ncall objShell.Run("virtual**down.bat",0,FALSE)')
# down_vbs_wrapper.close()
print "For p p t p on windows only, run virtual**up.bat before dialing to virtual**," \
"and run virtual**down.bat after disconnected from the virtual**."
def generate_android(metric):
results = fetch_ip_data()
upscript_header=textwrap.dedent("""\
#!/bin/sh
alias nestat='/system/xbin/busybox netstat'
alias grep='/system/xbin/busybox grep'
alias awk='/system/xbin/busybox awk'
alias route='/system/xbin/busybox route'
OLDGW=`netstat -rn | grep ^0\.0\.0\.0 | awk '{print $2}'`
""")
downscript_header=textwrap.dedent("""\
#!/bin/sh
alias route='/system/xbin/busybox route'
""")
upfile=open('virtual**up.sh','w')
downfile=open('virtual**down.sh','w')
upfile.write(upscript_header)
upfile.write('\n')
downfile.write(downscript_header)
downfile.write('\n')
for ip,mask,_ in results:
upfile.write('route add -net %s netmask %s gw $OLDGW\n'%(ip,mask))
downfile.write('route del -net %s netmask %s\n'%(ip,mask))
upfile.close()
downfile.close()
print "Old school way to call up/down script from openvirtual** client. " \
"use the regular openvirtual** 2.1 method to add routes if it's possible"
def fetch_ip_data():
#fetch data from apnic
print "Fetching data from apnic.net, it might take a few minutes, please wait..."
url=r'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest'
data=urllib2.urlopen(url).read()
cnregex=re.compile(r'apnic\|cn\|ipv4\|+\|+\|+\|a.*',re.IGNORECASE)
cndata=cnregex.findall(data)
results=[]
for item in cndata:
unit_items=item.split('|')
starting_ip=unit_items
num_ip=int(unit_items)
datenum=unit_items
imask=0xffffffff^(num_ip-1)
#convert to string
imask=hex(imask)
mask=*4
mask=imask
mask=imask
mask=imask
mask=imask
#convert str to int
mask=[ int(i,16 ) for i in mask]
mask="%d.%d.%d.%d"%tuple(mask)
#mask in *nix format
mask2=32-int(math.log(num_ip,2))
results.append((starting_ip,datenum,mask2))
return results
if __name__=='__main__':
parser=argparse.ArgumentParser(description="Generate routing rules for virtual**.")
parser.add_argument('-p','--platform',
dest='platform',
default='openvirtual**',
nargs='?',
help="Target platforms, it can be openvirtual**, mac, linux,"
"win, android. openvirtual** by default.")
parser.add_argument('-m','--metric',
dest='metric',
default=5,
nargs='?',
type=int,
help="Metric setting for the route rules")
args = parser.parse_args()
if args.platform.lower() == 'openvirtual**':
generate_ovirtual**(args.metric)
elif args.platform.lower() == 'linux':
generate_linux(args.metric)
elif args.platform.lower() == 'mac':
generate_mac(args.metric)
elif args.platform.lower() == 'win':
generate_win(args.metric)
elif args.platform.lower() == 'android':
generate_android(args.metric)
else:
print>>sys.stderr, "Platform %s is not supported."%args.platform
exit(1)
# DST-ADDRESS PREF-SRC GATEWAY DISTANCE
0 A S0.0.0.0/0 pppoe-out2 1
1 ADS0.0.0.0/0 10.126.128.1 0
2DS0.0.0.0/0 116.8.216.1 0
3 ADC10.126.128.1/32 10.126.216.244pppoe-out2 0
4 ADC116.8.216.1/32 116.8.216.16 pppoe-out1 0
5 ADC192.168.14.0/24 192.168.14.1 bridge 0
有空接着写,主要是遇到的问题 楼主实现了嘛?我和楼主一模一样,加一个QQ交流一下 168kingmu 发表于 2018-10-14 22:57
楼主实现了嘛?我和楼主一模一样,加一个QQ交流一下
总有些细节不尽如人意,但是给出的这些都是成功测试的 stevemorrislian 发表于 2018-10-15 22:03
我的dns解析次序是自己本地服务器的dnsmasq,然后是114.114.114.114,所以结果大多不是电信的,目标移动 ...
我的dns是一台lede,所有流量都会经过软件中心的$$,他解析出来后经过ros出去,Facebook可能没有,微信有么,或者tg?不行的话我回去申请一下fb,不过fb要审核本人头像?可能需要一点时间 telegram....我申请fb了 我邮箱私聊你了 本帖最后由 168kingmu 于 2018-10-20 12:46 编辑
这是我现在的拓扑图
ROS(IP:192.168.14.1)负责DHCP和拨号
LEDE(IP:192.168.14.2)作为DNS和网关负责梯子和去广告
https://static.chiphell.com/forum/201708/15/170209gcbcgvct1y3c6wtn.png
PPPOE-OUT2是移动宽带,我去网上下载的大陆IP列表名称是no未批恩,创建的桥接名称是bridge,需要所有lan口和局域网IP的国外网站进出都走移动,你看我这个设置对没有,特别是这个general-src.add和in.interface和add type选择了local并且取反,这些地方你教程好像都没有说,但是我按照了其他教程设置上去了
本帖最后由 168kingmu 于 2018-10-20 12:57 编辑
最后怎么测试设置成功了,非大陆走移动 大陆走电信呢
我好像设置不对,刚刚看了一下流量,我在看优酷和斗鱼流量都走移动去了没有走电信PPPoE-out1都没有流量,全是out2的移动流量,。。。
是我设置错了还是我移动是内网IPV4+内网IPV6的地址,电信是IP是公网的IPV4地址,流量都从IPV6走了?但是我访问的地址已经都是IPV4的吧 是不是要在下载一个电信的ipv4列表来设置??? 168kingmu 发表于 2018-10-20 12:11
这是我现在的拓扑图
ROS(IP:192.168.14.1)负责DHCP和拨号
LEDE(IP:192.168.14.2)作为DNS和网关 ...
没看懂你的桥接是啥功能,请说清楚 168kingmu 发表于 2018-10-20 12:14
最后怎么测试设置成功了,非大陆走移动 大陆走电信呢
根据目标IP做traceroute测试,我把结果贴出来就是这个意思 168kingmu 发表于 2018-10-20 13:08
是我设置错了还是我移动是内网IPV4+内网IPV6的地址,电信是IP是公网的IPV4地址,流量都从IPV6走了?但是我 ...
terminal下,命令:
IP - Routes - print
路由怎么设置的?
页:
[1]
2