本帖最后由 maozhenyu 于 2020-5-30 13:27 编辑
这个问题的来源是:(1)部分使用Cisco Anyconnect当VPN的网络部署方会设置本地的路由模式为Split Include,只让需要的流量通过VPN,其余部分的继续走本地网络,减轻部署方服务器的负担。然而此时用户需要所有流量全都走这个VPN,或者至少指定的网站走这个VPN(懂的人自然懂这是要干什么)(2)部分VPN部署方强行带走了所有Traffic(Tunneling All Traffic),导致需要访问无关资源的时候访问速度不理想。
上述两个场景都涉及到需要在连接建立后,手动添加/删除路由表。那么我们先来试试直接改路由表行不行
1. netstat -ar
可以当前的路由表,里面能看到一些VPN路由记录
[Bash shell] 纯文本查看 复制代码 Destination Gateway Flags Refs Use Netif Expire
128.97 vpn-whatever.edu UGSc 0 0 utun2
128.32 vpn-whatever.gov UGSc 0 0 utun2
192.168.0 link#7 UCS 1 0 en2 !
255.255.255.255/32 link#7 UCS 0 0 en2 !
很明显,Netif指向utun2的记录就是VPN将会带走的流量。如果我们试图增加一条路由记录:
[Bash shell] 纯文本查看 复制代码 sudo route -nv add -net 172.217.6.4/32 -interface utun1 -static
再查看路由表,发现毫无变化。甚至你多执行几次,他都不会提示你有重复记录。看起来Cisco的客户端很有可能做了什么坏事,把我们对路由表的修改给拦截了。
打开vpnagentd进行分析,搜索了一下route、monitor、hook等关键词运气有点好,直接在Import表里找到了CHostConfigMgr::StartInterfaceAndRouteMonitoring(void)这样一个函数,函数的来源是/opt/cisco/anyconnect/lib/libvpnagentutilities.dylib。PS. 后来在stackoverflow上查到了有先人已经这样做过了,不过那个时候的方法现在有很多已经不好用了,而且没查到Windows版的解决方案,后文中我会提及。
查了一下caller,发现有一个判断,判断返回得是0才能继续执行下去。
Linux和Mac上直接可以在vpnagentd里下手,
直接改函数绑定的地方就行,把整段代码给nop掉问题就能解决。(因为是x86_64的程序,而caller入参rax为0,rax会继续保持0,这样返回值就默认为0了)
Windows下就比较愚蠢了,程序还是32位的。。。得在对应的vpnagentutilities.dll里改,不能简单地用ret,因为此时eax值不为0,程序会报错退出。那么就在前面加一段mov eax, 0不就好了,优雅一点写xor eax, eax可以少改几个字节。
这样就搞定了。Linux/Mac下直接终止vpnagentd重启一次即可,Windows下得重启vpnagent.exe对应的系统服务。然后再连接Cisco Anyconnect,尝试添加路由表
添加两次,发现显示记录重复了。使用netstat -ar可以看到路由表了。使用traceroute也能注意到该IP地址的路由指向.......嗯?为什么连不通?ping一下呢?Hmm,ping不通?直接访问呢?打不开,什么鬼。
发现问题了,Anyconnect的客户端设置了一个类似防火墙的策略,禁止非内置路由表以外的访问。(在Windows下会表现为General Failure/一般错误,稍有经验的人就会意识到这是防火墙的问题)
这个问题的解决方案在Mac和Linux上还是一如既往的straightforward。肯定出现在packet filter里,只要轻轻地:
[Bash shell] 纯文本查看 复制代码 sudo pfctl -f ohmygod.conf
conf文件内写:
pass out log on utun1 inet from 0.0.0.0/0 to 0.0.0.0/0 tag cisco_anyconnect_vpn_pass
pass in log on utun1 inet from 0.0.0.0/0 to 0.0.0.0/0 tag cisco_anyconnect_vpn_pass
随着回车键发出的愉悦声音,你会惊讶地发现
[Bash shell] 纯文本查看 复制代码 traceroute to 172.217.6.4 (172.217.6.4), 64 hops max, 52 byte packets
1 omg.myvpn.edu (192.17.88.29) 74.064 ms 73.639 ms 73.663 ms
*****
*****
然后发出内心的感叹:“啊,通了。”
然而在Windows版,客户端的逻辑不太一样,事情变得复杂起来。我大概用了半天的时间,寻找那些调用到底层防火墙/Filter的API,然后回溯试图寻找程序,替换,尝试,失败,替换,尝试,失败。
(省略寻找的过程。大致上是从可能的代码片段找起,然后向上溯源找出来的)
最终发现了两个函数 CHostConfigMgr::ApplyDynamicFilteringOnNewInterfaces 和 CHostConfigMgr::applyFilterConfiguration
patch这两个函数,用之前所说的同样方法干掉这个函数之后,Windows下也通了。
|