用 Rust 写了一个获取公网 IP 的小程序。
其实本来不想造这个轮子的,但是发现国内能稳定提供获取 IP 的服务少之又少,要么不稳定,要么会有各种限流。
今天突发奇想,NAT 打洞用的 STUN 服务本身就会返回客户端的 IP 地址,国内有不少大厂维护的 STUN 服务器,直接用肯定是最稳定的(因为大厂本身自己的服务也需要用到)。这些 STUN 服务器的稳定性应该不是个人搭建的 IP 查询服务能比的,跑路被打的风险也小很多。
简单 Google 了一下,竟然还没有人做过专门用来做这个的程序。我就基于 Rust 的 stun Crate example 改了一个。
用起来非常简单,直接到 Release 页面下载自己架构的可执行文件 chmox +x uip 或者 cargo install uip 即可。编译的二进制大小也进行了优化,只有 1 MB 多点,也没有别的运行时依赖。
不带参数默认使用 Google 的 STUN 服务器,但是也可以使用国内的服务器,比如:
$ uip
203.0.113.1
$ uip stun.qq.com
203.0.113.1
$ uip stun.miwifi.com
203.0.113.1
通过返回值是否为 0 可以判断是否成功获得 IP 地址。
也欢迎大家分享可以使用的公开 STUN 服务器地址,可以在项目 README.md 里提 PR 。
更多能用的 STUN 服务器:
CF:
$ uip stun.cloudflare.com
$ uip -4 stun.cloudflare.com # IPv4 only
国内 B 站的:
$ uip stun.chat.bilibili.com
|  |      1Aloento      2023-04-11 03:28:25 +08:00 via iPhone 这个好 | 
|      2Ricky123      2023-04-11 09:00:52 +08:00 支持+1, 作者要不要发布到 brew | 
|      3patrickyoung      2023-04-11 09:03:19 +08:00 via iPhone | 
|  |      4molezznet      2023-04-11 09:03:52 +08:00 我把默认的改成 stun.syncthing.net 。 这样内外都能用了 否则出现 `Error: ErrTransactionTimeOut` | 
|  |      5OutOfMemoryError      2023-04-11 09:06:16 +08:00 我用的 4.ipw.cn | 
|  |      8asmoker      2023-04-11 09:21:35 +08:00 via Android curl ip.threep.top | 
|      9kenvix      2023-04-11 09:32:17 +08:00 可以做到 KB 级吗,路由器上 1MB 还是太紧张了 | 
|      110o0O0o0O0o      2023-04-11 09:49:27 +08:00  1 还有 telnet 方式和 DNS 方式: 例如 dig -t txt o-o.myaddr.l.google.com @ns1.google.com +short dig myip.opendns.com @resolver1.opendns.com +short dig whoami.akamai.net. @ns1-1.akamaitech.net. +short telnet telnetmyip.com 它们协议基础简单,也许真的能达到如 #9 所说的 KB 级?不过不清楚国内大厂有没有这类公益服务器。 | 
|      15cq65617875      2023-04-11 13:53:08 +08:00 | 
|      17yinmin      2023-04-11 15:40:29 +08:00  1 还有 1 个地址能获取 IP 地址的: https://www.cloudflare.com/cdn-cgi/trace 给 1 段 python 函数,给需要做 ddns 的参考 ``` import re import requests import socket def find_my_ip(): url = 'https://www.cloudflare.com/cdn-cgi/trace' requests.packages.urllib3.util.connection.HAS_IPV6 = False match = re.search( r'ip=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', requests.get(url).text) if match: return match.group(1) else: return None print(find_my_ip()) ``` | 
|      18slowman      2023-04-11 15:59:13 +08:00  1 为什么之前没有这种工具 因为从 stun 获取 IP 是 stun 套件的其中一个示例功能,少有人单独掏出来 show 的 举例如 https://github.com/pion/stun/tree/master/cmd/stun-client ./stun_client 1.1.1.1:10101 | 
|      19slowman      2023-04-11 16:08:32 +08:00  2 telnet netgeartec.ga 8080 Connected to netgeartec.ga. Escape character is '^]'. HI HELLO 2.9 (2.9.2) 2021-11-30.2159.ffae0e0 GETIP YOURIP 1.1.1.1 speedtest.net 提供的 8080 端口上的服务器也都支持 GETIP 指令返回 IP | 
|  |      20UnknoownUser      2023-04-11 17:17:08 +08:00 via iPhone | 
|  |      21mikewang      2023-04-11 17:38:15 +08:00 via iPhone | 
|  |      22bagel      2023-04-11 17:45:04 +08:00 名字好评,功能不好说,下个二进制专门干这个事感觉稍麻烦。 | 
|      24crazyweeds      2023-04-11 22:55:08 +08:00 | 
|  |      25qsnow6      2023-04-11 23:50:30 +08:00 使用 myip.ipip.net 和 ip.sb 的人都没有长期使用这些服务,因为长期使用这些服务的人都知道它们不太可靠。我之前在家里运行了一个定时查询公网提交到 DDNS 的脚本,发现这两个服务经常会拒绝服务或者打不开。我猜测这可能是因为请求过多触发了风控。 我第一次听说这个 STUN 服务,非常感谢! 顺便也分享我使用的查询 IP 的接口, 非常稳定: http://checkip.amazonaws.com/ 。 | 
|  |      26xiangyuecn      2023-04-11 23:52:23 +08:00 今天刚好在找免费 turn 服务,qq 的也挺好用,本地网卡 ip 、外网 ip 统统拿下 var conn=new RTCPeerConnection({iceServers:[{ urls:["stun:stun.qq.com"] }]}) conn.onicecandidate=function(e){ if(e.candidate){ if(/([\d\.]+) \d+ typ (\w+)/.test(e.candidate.candidate)) console.log(RegExp.$2+" ip: "+RegExp.$1); }else{ console.log("完成"); } } conn.createDataChannel("test") var offer=await conn.createOffer() conn.setLocalDescription(offer) | 
|  |      27xiangyuecn      2023-04-11 23:59:27 +08:00 STUN 在线测试 https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ 两个域名看起来比较老牌的服务,好像都是德国的: stun.sipgate.net stun.voipstunt.com | 
|  |      28dndx OP  1 @qsnow6 没错,我测试 ipip 也经常超时或者跳出来 5 秒盾,总体来说稳定性还是达不到要求。 国内能提供稳定 IP 查询接口的太少了。找来找去还是大厂的 STUN 服务器最稳定,比如 B 站的就是他们用来做直播 WebRTC P2P 的,甚至还写了优化文章: https://www.bilibili.com/read/cv19672394?from=articleDetail ,必然比各种公益性的服务要靠谱点。 | 
|  |      29dndx OP @0o0O0o0O0o 公益的就难了,大厂 STUN 本来设计的就不是公益服务,所以可用性要靠谱点...国内的公益服务基本都不持久 | 
|  |      30dndx OP @qsnow6 实际上 `stun.qq.com` 甚至还做了 GeoDNS 国内分区解析,算是很用心了。可用性不太需要担心,甚至可以顺带作为网络通断的判断。 | 
|  |      32someonedeng      2023-04-12 00:56:01 +08:00 ip.sb 已经刻进 dna | 
|      33crazyweeds      2023-04-12 01:11:16 +08:00 @Ricky123 确实发布一下比较方便,虽然我个人网站支持,但确实命令行来得快。 | 
|  |      34serafin      2023-04-12 05:00:42 +08:00 我发个长亿点点的 curl -s https://www.cloudflare.com/cdn-cgi/trace | awk -F= '/^ip/{print $2}' curl -s https://1.1.1.1/cdn-cgi/trace | awk -F= '/^ip/{print $2}' curl -s visa.com/cdn-cgi/trace | awk -F= '/^ip/{print $2}' | 
|  |      35tux      2023-04-12 06:59:42 +08:00 怎么没有 windows 版? | 
|  |      36swulling      2023-04-12 08:20:22 +08:00 Python 的话直接用 aiostun 库就行了。 | 
|  |      37v2wtf      2023-04-12 09:16:32 +08:00 提个意见:主要面向国内的程序,不要默认 G 家服务器。 这种东西最重要的事情之一是:方便。 如果默认 G 家服务器,那么每次还得手动输入个国内服务器地址,或者写个 shell 脚本包一道。 这么麻烦,我为何不直接 curl ip.sb? | 
|  |      38v2wtf      2023-04-12 09:19:40 +08:00 除上面的意见之外,我觉得 OP 这个思路是对的。 不需要自己搭建服务器,有大厂稳定性,零依赖的东西用起来真的很爽。 | 
|  |      39dndx OP @v2wtf 感谢建议。实际上 G 家的 STUN 服务器在国内用起来也没问题,所以这个默认值也不是完全没道理。UDP 3478 比 TCP 443 被阻塞的概率也低多了。 | 
|  |      40v2wtf      2023-04-12 15:35:32 +08:00  1 @dndx 我下载回来第一次运行 uip 就是超时,看了下上面说的换了国内服务器才测试成功,所以才给出你提的建议。 第一次运行直接就失败,所以默认服务器成功率就不可能高。 | 
|  |      42qsnow6      2023-04-12 20:11:54 +08:00 @dndx #41 ipv4 也有一定机率会连不通, 可能是 Google 的服务在墙内被干扰了. ```shell $ ./uip_x86_64-unknown-linux-musl -4 Error: ErrTransactionTimeOut ``` | 
|  |      43dndx OP  1 @qsnow6 我觉得你说的很有道理,在 ipip 上测了一下,好像 `stun.l.google.com` 在国内一些地方的确是解析不出来(主要是联通)。 刚发布了一个新版本 `v0.1.5`,在这个版本里默认的服务器已经改为了 `stun.cloudflare.com`,应该会好一些。考虑到国外的用户,不太想用国内的服务器作为默认值,希望理解。 | 
|      45kaddusabagei38      2023-04-13 10:52:12 +08:00 这个思路很棒 | 
|  |      46devliu1      2023-04-13 11:12:00 +08:00 curl ip.3322.org | 
|  |      47AokiHina      2023-04-13 16:25:51 +08:00  1 @tux https://github.com/amorphobia/uip 已经有大佬改出来了 windows 下的 target | 
|  |      48dndx OP @Ghonewyn  @tux Windows 版已经打出来了 https://github.com/dndx/uip/releases/tag/v0.1.6 感谢 amorphobia 贡献 https://github.com/dndx/uip/pull/1 我没有 Windows 系统,希望能有人帮忙测试一下能不能用。 | 
|      49dorothyREN      2023-04-16 13:03:49 +08:00 | 
|  |      50mohumohu      2023-04-20 16:29:48 +08:00 OP 的项目不错,是否可以支持 SOCKS5 代理?因为 stun 用来测 socks 的 nat type 挺方便的,最好支持一次性重试多个列表。 另外公网获取 IP 的也有挺多 URL 可以用的,OP 可以看看这个 DDNS 脚本里面内置了一些获取 IP 的 URL: https://github.com/kkkgo/UE-DDNS | 
|      51fox233      2023-04-28 14:54:21 +08:00 releases 里面为啥没有 x86_64 的 Linux 文件呢?只有安卓的和 arm 的 | 
|  |      52dndx OP | 
|      53EsWann      2023-07-07 03:10:18 +08:00 可以看下 https://www.ipip.sh/ |