nondanee / UnblockNeteaseMusic

Revive unavailable songs for Netease Cloud Music
MIT License
17.42k stars 2.52k forks source link

安卓设备只有重启第一次可以成功解锁 #423

Closed mzz2017 closed 4 years ago

mzz2017 commented 4 years ago

环境

安卓设备 网易云V7.0.20最新版

linux网关,通过tproxy全局代理转发请求至8080端口。

启动参数为

docker run -d -p 8080:8080 --name unblock nondanee/unblockneteasemusic -p 8080:8081 -e https://music.163.com

描述问题

无论是全部代理,还是部分代理,在程序启动后的第一次点进歌单后可解锁歌曲,再次进入则变灰,随后无论如何都是灰色。

复现步骤

  1. 启动程序,进入网易云,进入歌单,成功解锁,等待5秒,退出歌单。

  2. 进入歌单,解锁失败。

  3. 进入歌单,解锁失败。

  4. 重启网易云,解锁失败。

  5. 重启程序。

  6. 进入歌单,解锁成功,等待5秒,退出歌单。

  7. 进入歌单,解锁失败。

  8. 重启网易云,解锁失败。

复现几率在70%左右。

各类设备情况

iOS设备解锁正常

Linux网关解锁正常

安卓设备解锁异常(安装证书后仍然异常)

nondanee commented 4 years ago

Android 端安装用户证书无效 https://github.com/nondanee/UnblockNeteaseMusic/issues/30#issuecomment-472538422

我用 WLAN 代理无法复现

判断可能是 sni 没拦到,能 debug 的话把 sni 打印出来看一看https://github.com/nondanee/UnblockNeteaseMusic/blob/91e631db87920c67f92161a724a2d96472ad33cd/src/hook.js#L209

linux网关,通过tproxy全局代理转发请求至8080端口。

这是 root 了吧?root 把用户证书改成系统证书试试

mzz2017 commented 4 years ago

步骤2的日志

...(begin)

TUNNEL > 59.111.239.61:443
TUNNEL > 59.111.179.213:443
TUNNEL > 59.111.239.61:443
url Url {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: '59.111.179.213:443',
  port: '443',
  hostname: '59.111.179.213',
  hash: null,
  search: null,
  query: null,
  pathname: '/',
  path: '/',
  href: 'https://59.111.179.213:443/'
} sni: null
url Url {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: '59.111.239.61:443',
  port: '443',
  hostname: '59.111.239.61',
  hash: null,
  search: null,
  query: null,
  pathname: '/',
  path: '/',
  href: 'https://59.111.239.61:443/'
} sni: null
url Url {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: '59.111.239.61:443',
  port: '443',
  hostname: '59.111.239.61',
  hash: null,
  search: null,
  query: null,
  pathname: '/',
  path: '/',
  href: 'https://59.111.239.61:443/'
} sni: null
(end)

这是 root 了吧?root 把用户证书改成系统证书试试

archlinux的笔记本作为网关,用v2ray把相关流量都转发到8080端口。说来也巧,之前有些时候v2ray拦sni也没拦到。

mzz2017 commented 4 years ago

设备没有root,这个问题应该和证书没什么关系吧

mzz2017 commented 4 years ago

等待一段时间再次进入歌单偶然解锁成功日志:

TUNNEL > localhost:8081
TUNNEL > localhost:8081
TUNNEL > localhost:8081
TUNNEL > localhost:8080
MITM > interface3.music.163.com 
TUNNEL > localhost:8080
MITM > interface3.music.163.com 
TUNNEL > api.iplay.163.com:443
url Url {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: 'api.iplay.163.com:443',
  port: '443',
  hostname: 'api.iplay.163.com',
  hash: null,
  search: null,
  query: null,
  pathname: '/',
  path: '/',
  href: 'https://api.iplay.163.com:443/'
} sni: api.iplay.163.com
MITM > interface3.music.163.com 
TUNNEL > localhost:8081
MITM > interface3.music.163.com 
TUNNEL > clientlog3.music.163.com:443
url Url {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: 'clientlog3.music.163.com:443',
  port: '443',
  hostname: 'clientlog3.music.163.com',
  hash: null,
  search: null,
  query: null,
  pathname: '/',
  path: '/',
  href: 'https://clientlog3.music.163.com:443/'
} sni: clientlog3.music.163.com
nondanee commented 4 years ago

确实没 sni 啊 sni: null

下载 pac 文件打开看看里面有没有包含

59.111.239.61
59.111.179.213

没有的话手动加到 target.host 里

https://github.com/nondanee/UnblockNeteaseMusic/blob/91e631db87920c67f92161a724a2d96472ad33cd/src/hook.js#L25

mzz2017 commented 4 years ago

有时步骤2连TUNNEL都没有…… 我已经将http和tls流量都转发到8080了

mzz2017 commented 4 years ago

下载 pac 文件打开看看里面有没有包含

哪个地方的pac文件?

nondanee commented 4 years ago

这个问题和证书没有直接关系 但是如果证书被信任也能解决

如果主站 https API (music.163.com) 用域名访问是"正常"的 应该不会再尝试用 httpdns 查出来 ip 强制连接到指定 https API 就没有这些 TUNNEL > ip

nondanee commented 4 years ago

http://<Server Name:PORT>/proxy.pac

mzz2017 commented 4 years ago

确实在termux中curl -v https://music.163.com 后提示CA证书有问题。

function FindProxyForURL(url, host) {
    if (host == 'music.163.com' || host == 'interface.music.163.com' || host == 'interface3.music.163.com' || host == 'apm.music.163.com' || host == 'apm3.music.163.com' || host == '59.111.239.61' || host == '59.111.239.62' || host == '59.111.179.213' || host == '59.111.181.35' || host == '59.111.181.38' || host == '59.111.181.60' || host == '223.252.199.66' || host == '223.252.199.67' || host == '59.111.160.195' || host == '59.111.160.197' || host == '193.112.159.225' || host == '118.24.63.156' || host == '115.236.121.1' || host == '115.236.118.33' || host == '39.105.63.80' || host == '47.100.127.239' || host == '2407:ae80:200:1001::20' || host == '59.111.239.61' || host == '59.111.239.62' || host == '59.111.179.213') {
        return 'PROXY localhost:8080'
    }
    return 'DIRECT'
}

包含上述地址。

设系统代理后正常。

有可能有其他解决方案吗。

nondanee commented 4 years ago

不清楚,第二个端口不要开试试看吧

mzz2017 commented 4 years ago

不清楚,第二个端口不要开试试看吧

这会导致Linux设备异常,不过没关系,谢谢你的帮助。

mzz2017 commented 4 years ago

今天manjaro上也出现了这个问题,可能是网络变化(网络中断和恢复)导致的,重启docker容器就好了。

这个问题玄学在重启UnblockNeteaseMusic就会好,而不是重启网易云,安卓也是。

nondanee commented 4 years ago

我似乎好像知道是为什么了 😂

nondanee commented 4 years ago

好像也没什么问题

https://github.com/nondanee/UnblockNeteaseMusic/blob/91e631db87920c67f92161a724a2d96472ad33cd/src/hook.js#L25

你把 hook.negotiate.before 这个整段去掉试一下吧 在这里会动态加 target,重启后会重置

mzz2017 commented 4 years ago

你把 hook.negotiate.before 这个整段去掉试一下吧 在这里会动态加 target,重启后会重置

仍然重启好一次。

mzz2017 commented 4 years ago

当时我应该是看到流量经过8080直接绕过了,因为直接打开music.163.com使用的是他原本的证书。

nondanee commented 4 years ago

麻烦用 curl 确认一下

export http_proxy=xxx
curl http://baidu.com

是内部网络挂了吗?或者端口 down 了?pac 还可以正常打开吗?

mzz2017 commented 4 years ago

现在不好复现那个时候的场景,我遇到之后再确认一下吧。

但现在安卓的那个问题是一直可以复现的。

nondanee commented 4 years ago

好👌

mzz2017 commented 4 years ago

问题已解决,将clientlog3.music.163.com屏蔽即可。

nondanee commented 4 years ago

好的,屏蔽 clientlog 会影响听歌记录,自己权衡一下 (感觉这个和重启没有太大关系)

mzz2017 commented 4 years ago

好的,屏蔽 clientlog 会影响听歌记录,自己权衡一下 (感觉这个和重启没有太大关系)

但实际上它确实奏效了。可以看到音源变灰之前请求了一次clientlog3,随后便似乎不再发送请求。

我看到他发往IP:443的请求,其Host也都是IP:443,似乎还是HTTP非TLS,且body为空,可以看出是一个无意义的GET请求,我没有逆向过不知道这段代码他想做什么。

如果你想复现并调试的话,可以在linux下使用v2ray作透明代理,v2ray配置相关流量转发到8080端口(可以参考docker-compose那个issue),并用电脑开热点,用安卓设备连接,无需填写代理,即可复现。

简单的有一些客户端帮助复现,比方说我在维护的V2RayA,以及Clash、Qv2ray等。

mzz2017 commented 4 years ago

一个好消息。

我将clientlog3.music.163.com加入hook.target.host后,同样解决了问题。

我猜测是否与x-napm-retry有关?

nondanee commented 4 years ago

复现和调试黑盒的意义不大,兜底的请求策略应该很复杂 一般情况下请求能拦截到即可,面面俱到也不太可能

嗯 target host 里之前有 clientlog,因为听歌记录的打点就保留了没拦截

x-napm-retry 会带上 retry 之前的出错信息,我给抹掉了,有多少作用不太清楚 (降级是我的期望行为不算错误,尽量不要给官方带来困扰)

mzz2017 commented 4 years ago

观察后发现MITM除了给clientlog3.music.163.com颁发了TLS证书以外没有任何修改,猜测网易云可能是在从clientlog3.music.163.com获得了可用的证书后,使得https降级不再进行,导致后续MITM失败。

nondanee commented 4 years ago

不是颁发证书,是导流到 https 端口上 我不可能自己处理二进制报文进行协商和握手 导流到 https 的端口后我只要处理 http 请求就可以了 https 端口和 http 端口共用一套 MITM 逻辑,也是可以修改的

问题应该在 keep-alive 上,之后的请求都使用了 clientlog 的那条 tcp 连接

mzz2017 commented 4 years ago

好的,屏蔽 clientlog 会影响听歌记录,自己权衡一下 (感觉这个和重启没有太大关系)

Hello, UnblockNeteaseMusic会对clientlog进行修改吗,为什么加入host会影响听歌记录呢

nondanee commented 4 years ago

不会修改,加入 host 会被拦截,拦截可能会导致请求失败 clientlog 是日志上报,重要性不高,不像业务接口那样有一系列降级兜底策略,类似 https 域名 > https IP > http ip > http 域名 ..... 如果连接被阻断了 (不开 https 端口的情况),或者因为证书异常而请求失败,可能都不会触发降级请求第二次 这只是我看到的现象,可能只是个别请求是这样,可能你那边会重新请求,具体策略我不知道

mzz2017 commented 4 years ago

不会修改,加入 host 会被拦截,拦截可能会导致请求失败 clientlog 是日志上报,重要性不高,不像业务接口那样有一系列降级兜底策略,类似 https 域名 > https IP > http ip > http 域名 ..... 如果连接被阻断了 (不开 https 端口的情况),或者因为证书异常而请求失败,可能都不会触发降级请求第二次 这只是我看到的现象,可能只是个别请求是这样,可能你那边会重新请求,具体策略我不知道

明白了,感谢解答。

我这里看到安卓设WLAN代理的情况下和拦截clientlog的情况是一样的,无法查看个人主页,说明应该是降级失败了。所以安卓这个代理方案一样会影响听歌记录。

nondanee commented 4 years ago

用户页确实是降级失败,https://github.com/nondanee/UnblockNeteaseMusic/issues/30#issuecomment-472538422 ,但无法查看不代表影响记录 听歌计数是在 clientlog 打点上报的 现在这样不会影响 你可以自己在安卓上测试听完以后有没有 +1 当然可能你把 clientlog 加入 target 也会 +1,那是最好的了 (具体策略我不知道,对不同客户端不同版本的影响也都不知道)