关于 Chrome 出现 ERR_UNSAFE_PORT 错误
TiDB 内置了一个 Web 服务(10080 端口),用 Chrome 访问时提示:
无法访问此网站网址为 http://xxx:10080/ 的网页可能暂时无法连接,或者它已永久性地移动到了新网址。 ERR_UNSAFE_PORT
关于 ERR_UNSAFE_PORT 错误,也只在网上找到一些零碎的答案,说 Chrome 为了安全禁封掉了这些端口,建议更换服务端的监听端口。出于好奇,我顺着 Chromium 源码找到返回 ERR_UNSAFE_PORT 的函数:
// file: net/http/http_stream_factory_job.cc int HttpStreamFactory::Job::DoStart() { ... if (!IsPortAllowedForScheme(destination_.port(), request_info_.url.scheme_piece())) { return ERR_UNSAFE_PORT; } ... return OK; }
以上,关键在 IsPortAllowedForScheme 函数,找到函数实现:
// file: net/base/port_util.cc bool IsPortAllowedForScheme(int port, base::StringPiece url_scheme) { // Reject invalid ports. if (!IsPortValid(port)) return false; LogAlpacaPort(port); // Allow explicitly allowed ports for any scheme. if (g_explicitly_allowed_ports.Get().count(port) > 0) return true; // Finally check against the generic list of restricted ports for all // schemes. for (int restricted_port : kRestrictedPorts) { if (restricted_port == port) return false; } return true; }
注意最后的 for 循环的对象 kRestrictedPorts,再找到 kRestrictedPorts 的定义:
const int kRestrictedPorts[] = { 1, // tcpmux 7, // echo 9, // discard 11, // systat 13, // daytime 15, // netstat 17, // qotd 19, // chargen 20, // ftp data 21, // ftp access 22, // ssh 23, // telnet 25, // smtp 37, // time 42, // name 43, // nicname 53, // domain 69, // tftp 77, // priv-rjs 79, // finger 87, // ttylink 95, // supdup 101, // hostriame 102, // iso-tsap 103, // gppitnp 104, // acr-nema 109, // pop2 110, // pop3 111, // sunrpc 113, // auth 115, // sftp 117, // uucp-path 119, // nntp 123, // NTP 135, // loc-srv /epmap 137, // netbios 139, // netbios 143, // imap2 161, // snmp 179, // BGP 389, // ldap 427, // SLP (Also used by Apple Filing Protocol) 465, // smtp+ssl 512, // print / exec 513, // login 514, // shell 515, // printer 526, // tempo 530, // courier 531, // chat 532, // netnews 540, // uucp 548, // AFP (Apple Filing Protocol) 554, // rtsp 556, // remotefs 563, // nntp+ssl 587, // smtp (rfc6409) 601, // syslog-conn (rfc3195) 636, // ldap+ssl 989, // ftps-data 990, // ftps 993, // ldap+ssl 995, // pop3+ssl 1719, // h323gatestat 1720, // h323hostcall 1723, // pptp 2049, // nfs 3659, // apple-sasl / PasswordServer 4045, // lockd 5060, // sip 5061, // sips 6000, // X11 6566, // sane-port 6665, // Alternate IRC [Apple addition] 6666, // Alternate IRC [Apple addition] 6667, // Standard IRC [Apple addition] 6668, // Alternate IRC [Apple addition] 6669, // Alternate IRC [Apple addition] 6697, // IRC + TLS 10080, // Amanda };
kRestrictedPorts 数组里存放了一些已知服务的端口,当通过 HTTP(S) 协议访问这些端口时都会报 ERR_UNSAFE_PORT 错误。为了弄清目的,我试着在 git log 里找到答案,如下:
$ git log --grep 10080 port_util.cc commit d6e884b99ffa8ad5f85ae13c5aa78dd297572f19 Author: Adam Rice <[email protected]> Date: Tue Apr 13 09:35:40 2021 +0000 Block port 10080 See Fetch Standard issue https://github.com/whatwg/fetch/issues/1191 for justification and background, and https://groups.google.com/a/chromium.org/g/blink-dev/c/CNpLNXx2wf0/m/Ehi3cx1YAQAJ for the intent-to-ship thread. BUG=1197299 Change-Id: Ie664726307fef0d8578ffbaea9793b74d722b58a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2814044 Commit-Queue: Adam Rice <[email protected]> Reviewed-by: Ryan Sleevi <[email protected]> Cr-Commit-Position: refs/heads/master@{#871865}
接着顺着 commit 里记录的 issue 链接(https://github.com/whatwg/fetch/issues/1191 )去找,原来 Chrome 是为了防止 NAT Slipstreaming 攻击而封锁的端口。