如何在命令行快速获取公网动态 IP 地址
<p data-id="pb60e94d-9b8jgmDH"><img title="如何在命令行快速获取公网动态 IP 地址" alt="如何在命令行快速获取公网动态 IP 地址" src="https://zhuji.jb51.net/uploads/img/202305/0be74df7af2542dfcd14f3422c4d1720.jpg"></p>
<p data-id="pd157317-YAjDEUSm">
如何确定公网IP地址是一个让很多家用宽带朋友们经常遇到的问题,毕竟固定IP地址总是价格不菲因而不适用于家庭宽带,而我们的电信宽带运营商(ISP)往往给我们分配的是动态IP地址,之所以称作为动态IP地址,是因为每次拨号得到的IP地址可能会不一样,还有更骚的操作就是有的运营商每天或不定期在某个时间刷新IP地址池,这样已经获得的IP地址将会被强制释放并分配新的IP地址。
</p>
<p data-id="pd157317-NGLPFHd5">
这对于我们一些运行在家用带宽下的服务带来了影响——需要重新设置服务端 IP 地址,比如监控、网络存储等等,这时候 DDNS 就发挥作用的,现在大部分路由器内置了 DDNS 客户端,比如花生壳等服务客户端,但是这些客户端存在收费、不稳定以及刷新间隔小等问题,对于自己有域名的朋友可以使用 DNS 服务商的 API 自己实现 IP 更新操作,比如阿里云(Aliyun)、Cloudflare 均可以实现。
</p>
<p data-id="pd157317-fWAbaWKh">
对于 DDNS 如何使用 API 更新不在本文叙述范围内,但调用 API 有个关键参数那就是公网IP地址,如何获取当前运营商分配的公网 IP地址呢?除了问路由器外(打开路由器管理界面找到 WAN 口信息)我们还可以通过一些网络服务进行检测。
</p>
<h3 id="h0613ccc-HdM0l37a" data-id="h0613ccc-HdM0l37a">
1. 使用 Shell 命令获取公网 IP 地址
</h3>
<h4 id="hdf2c2dd-OZT3lZS1" data-id="hdf2c2dd-OZT3lZS1">
浏览器方式
</h4>
<p data-id="pd157317-81hml3nX">
如果我们使用浏览器打开这个地址checkip.amazonaws.com你就会发现你的公网IP地址赫然在目,互联网上的服务器总是能够知道是什么 IP地址的客户端发起了连接,当然就可以通过这种方式获取公网 IP,同样功能的网站有很多,这里列举部分我收集到的:
</p>
<pre>https<span class="cm-punctuation">:</span><span class="cm-operator">//</span>checkip<span class="cm-variable-2">.amazonaws</span><span class="cm-variable-2">.com</span> https<span class="cm-punctuation">:</span><span class="cm-operator">//</span>api<span class="cm-variable-2">.ipify</span><span class="cm-variable-2">.org</span> https<span class="cm-punctuation">:</span><span class="cm-operator">//</span>ifconfig<span class="cm-variable-2">.me</span><span class="cm-operator">/</span>ip
https<span class="cm-punctuation">:</span><span class="cm-operator">//</span>icanhazip<span class="cm-variable-2">.com</span> https<span class="cm-punctuation">:</span><span class="cm-operator">//</span>ipinfo<span class="cm-variable-2">.io</span><span class="cm-operator">/</span>ip
https<span class="cm-punctuation">:</span><span class="cm-operator">//</span>ipecho<span class="cm-variable-2">.net</span><span class="cm-operator">/</span>plain
https<span class="cm-punctuation">:</span><span class="cm-operator">//</span>checkipv4<span class="cm-variable-2">.dedyn</span><span class="cm-variable-2">.io</span> </pre>
<h4 id="hdf2c2dd-6NZCd3hS" data-id="hdf2c2dd-6NZCd3hS">
cURL 方式
</h4>
<p data-id="pd157317-ajSadq35">
在命令行下我们当然不能为这点小事随便启动浏览器,我们可以请出另外一个功能强大的工具,那就是curl,cURL 是一个利用URL语法在命令行下工作的文件传输工具,关于cURL的快速用法可以参考阮一峰的网络日志《curl 的用法指南》,这里不再详述,最简单的用法就是curl 你要请求的网址,比如curl checkip.amazonaws.com。
</p>
<h4 id="hdf2c2dd-VnNOY4d9" data-id="hdf2c2dd-VnNOY4d9">
使用 dig 命令
</h4>
<p data-id="pd157317-CkZZAcWT">
首次在别人脚本中看到这个方式获取公网IP觉得比较新奇,命令如下:
</p>
<pre>dig <span class="cm-operator">+</span>short myip<span class="cm-variable-2">.opendns</span><span class="cm-variable-2">.com</span> @resolver1<span class="cm-variable-2">.opendns</span><span class="cm-variable-2">.com</span> </pre>
<p data-id="pd157317-jfENqsC4">
这个是由OpenDNS提供的服务,如果你的主机上没有安装dig命令,对于Debian系列系统可以通过apt-get install dnsutils安装,这个命令的原理是指定resolver1.opendns.com为域名myip.opendns.com的解析服务器,为什么要指定,主要是避免 DNS 下游服务器缓存,另外这个指定的解析服务器被 OpenDNS 进行了特殊配置,其始终将域名myip.opendns.com解析为发起 DNS 请求的客户端 IP 地址,这样也就实现了查找公网 IP的功能。
</p>
<p data-id="pd157317-mb1MT2If">
这个和 cURL 方式比有什么优势呢?当然是数据量更小传输更快,毕竟使用 cURL 发起 HTTP 请求必然会导致协议头等无关信息的交换,如果启用了 HTTPS/TLS 那么还要进行加密协商,效率会比较低,当然这种方式的缺点就是 DNS 查询容易被运营商审计和过滤,稳定性略差,不过我测试下来除了偶尔查询失败外其余情况是完全 OK 的。
</p>
<h3 id="h0613ccc-8mVHIg9K" data-id="h0613ccc-8mVHIg9K">
2. 使用 Shell 脚本获取公网 IP 地址
</h3>
<p data-id="pd157317-JIGvXk2R">
至此我有个新的主意,那就是首先采用 dig 命令快速检索公网 IP 地址,如果失败则切换到 cURL 的方式,为了避免 cURL 单一服务器失败,采用轮询或者随机的方式,尽可能提高成功率。
</p>
<p data-id="pd157317-e7J5Gcte">
使用 Bash Shell 脚本 do it,比如获取公网 IPv4 的脚本如下:
</p>
<pre>#<span class="cm-operator">!/</span>bin<span class="cm-operator">/</span>bash
# This script try to ensure gets the current IP address <span class="cm-bracket">(</span><span class="cm-keyword">as</span> assigned <span class="cm-keyword">by</span> the ISP<span class="cm-bracket">)</span> <span class="cm-keyword">from</span> # OpenDNS <span class="cm-keyword">and</span> other online services <span class="cm-keyword">as</span> fallbacks
hosts<span class="cm-operator">=</span><span class="cm-bracket">(</span><span class="cm-string">"checkip.amazonaws.com"</span> <span class="cm-string">"api.ipify.org"</span> <span class="cm-string">"ifconfig.me/ip"</span> <span class="cm-string">"icanhazip.com"</span> <span class="cm-string">"ipinfo.io/ip"</span> <span class="cm-string">"ipecho.net/plain"</span> <span class="cm-string">"checkipv4.dedyn.io"</span><span class="cm-bracket">)</span> CURL<span class="cm-operator">=</span>`which curl`
DIG<span class="cm-operator">=</span>`which dig`
check<span class="cm-operator">=</span>$<span class="cm-bracket">(</span>$DIG <span class="cm-operator">+</span>short myip<span class="cm-variable-2">.opendns</span><span class="cm-variable-2">.com</span> @resolver1<span class="cm-variable-2">.opendns</span><span class="cm-variable-2">.com</span> A<span class="cm-bracket">)</span> if <span class="cm-bracket">[</span> <span class="cm-operator">!</span> $<span class="cm-variable-3">? </span><span class="cm-operator">-</span>eq <span class="cm-number">0</span> <span class="cm-bracket">]</span> <span class="cm-operator">||</span> <span class="cm-bracket">[</span> <span class="cm-operator">-</span>z <span class="cm-string">"$check"</span> <span class="cm-bracket">]</span> <span class="cm-operator">||</span> <span class="cm-bracket">[</span><span class="cm-bracket">[</span> <span class="cm-operator">!</span> $check <span class="cm-operator">=~</span> <span class="cm-operator">^</span><span class="cm-bracket">[</span><span class="cm-number">0</span><span class="cm-operator">-</span><span class="cm-number">9</span><span class="cm-bracket">]</span><span class="cm-operator">+</span>\.<span class="cm-bracket">[</span><span class="cm-number">0</span><span class="cm-operator">-</span><span class="cm-number">9</span><span class="cm-bracket">]</span><span class="cm-operator">+</span>\.<span class="cm-bracket">[</span><span class="cm-number">0</span><span class="cm-operator">-</span><span class="cm-number">9</span><span class="cm-bracket">]</span><span class="cm-operator">+</span>\.<span class="cm-bracket">[</span><span class="cm-number">0</span><span class="cm-operator">-</span><span class="cm-number">9</span><span class="cm-bracket">]</span><span class="cm-operator">+</span>$ <span class="cm-bracket">]</span><span class="cm-bracket">]</span><span class="cm-punctuation">;</span> then
echo <span class="cm-string">"Unable to get your public IP address by OpenDNS service, try to another way."</span> <span class="cm-keyword">count</span><span class="cm-operator">=</span>$<span class="cm-bracket">{</span>#hosts<span class="cm-bracket">[</span>@<span class="cm-bracket">]</span><span class="cm-bracket">}</span> while <span class="cm-bracket">[</span> <span class="cm-operator">-</span>z <span class="cm-string">"$check"</span> <span class="cm-bracket">]</span> <span class="cm-operator">&&</span> <span class="cm-bracket">[</span><span class="cm-bracket">[</span> $count <span class="cm-operator">-</span>ne <span class="cm-number">0</span> <span class="cm-bracket">]</span><span class="cm-bracket">]</span><span class="cm-punctuation">;</span> do
selectedhost<span class="cm-operator">=</span>$<span class="cm-bracket">{</span>hosts<span class="cm-bracket">[</span> $RANDOM <span class="cm-operator">%</span> $<span class="cm-bracket">{</span>#hosts<span class="cm-bracket">[</span>@<span class="cm-bracket">]</span><span class="cm-bracket">}</span> <span class="cm-bracket">]</span><span class="cm-bracket">}</span> check<span class="cm-operator">=</span>$<span class="cm-bracket">(</span>$CURL <span class="cm-operator">-</span><span class="cm-number">4</span>s https<span class="cm-punctuation">:</span><span class="cm-operator">//</span>$selectedhost <span class="cm-operator">|</span> grep <span class="cm-string">'[^[:blank:]]'</span><span class="cm-bracket">)</span> <span class="cm-operator">&&</span> <span class="cm-bracket">{</span> if <span class="cm-bracket">[</span> <span class="cm-operator">-</span>n <span class="cm-string">"$check"</span> <span class="cm-bracket">]</span> <span class="cm-operator">&&</span> <span class="cm-bracket">[</span><span class="cm-bracket">[</span> $check <span class="cm-operator">=~</span> <span class="cm-operator">^</span><span class="cm-bracket">[</span><span class="cm-number">0</span><span class="cm-operator">-</span><span class="cm-number">9</span><span class="cm-bracket">]</span><span class="cm-operator">+</span>\.<span class="cm-bracket">[</span><span class="cm-number">0</span><span class="cm-operator">-</span><span class="cm-number">9</span><span class="cm-bracket">]</span><span class="cm-operator">+</span>\.<span class="cm-bracket">[</span><span class="cm-number">0</span><span class="cm-operator">-</span><span class="cm-number">9</span><span class="cm-bracket">]</span><span class="cm-operator">+</span>\.<span class="cm-bracket">[</span><span class="cm-number">0</span><span class="cm-operator">-</span><span class="cm-number">9</span><span class="cm-bracket">]</span><span class="cm-operator">+</span>$ <span class="cm-bracket">]</span><span class="cm-bracket">]</span><span class="cm-punctuation">;</span> then
break
else
check<span class="cm-operator">=</span><span class="cm-string">""</span> <span class="cm-keyword">count</span><span class="cm-operator">=</span>$<span class="cm-bracket">(</span>expr $count <span class="cm-operator">-</span> <span class="cm-number">1</span><span class="cm-bracket">)</span> echo <span class="cm-string">"The host $selectedhost returned an invalid IP address."</span> fi <span class="cm-bracket">}</span> <span class="cm-operator">||</span> <span class="cm-bracket">{</span> check<span class="cm-operator">=</span><span class="cm-string">""</span> <span class="cm-keyword">count</span><span class="cm-operator">=</span>$<span class="cm-bracket">(</span>expr $count <span class="cm-operator">-</span> <span class="cm-number">1</span><span class="cm-bracket">)</span> echo <span class="cm-string">"The host $selectedhost did not respond."</span> <span class="cm-bracket">}</span> done
fi
if <span class="cm-bracket">[</span> <span class="cm-operator">-</span>z <span class="cm-string">"$check"</span> <span class="cm-bracket">]</span><span class="cm-punctuation">;</span> then
echo <span class="cm-string">"Unable to get your public IP address. Please check your internet connection."</span> exit <span class="cm-number">1</span> fi
echo <span class="cm-string">"Your public IP address is $check"</span> exit <span class="cm-number">0</span> </pre>
<p data-id="pd157317-0pELpJIg">
上述脚本可以看出首先我使用 dig 方式查询 OpenDNS,如果查询失败或者返回为空或者不是 IP 地址,那么进入cURL模式,这里将可用服务器添加到 hosts 列表,并且随机抽取一个进行cURL,这里使用了curl -4s参数-4s分别表示仅使用 IPv4 方式连接(确保获取 IPv4 地址)和抑制进度条和错误信息,如果抽取的服务发生错误,那么进入循环再抽取一个,直到循环满最大 hosts 数停止。
</p>
<h3 id="h0613ccc-NET5A9KD" data-id="h0613ccc-NET5A9KD">
3. 总结
</h3>
<p data-id="pd157317-en0tE3rs">
大部分脚本甚至一些程序仅使用了一种方式获取公网 IP,但是互联网上这些服务往往是不可靠的,如果你所选用的服务出现故障,那么将会影响到你后续业务的开展,所以本文的核心思想还是多个备份,另外对于 cURL 方式采用随机确保所谓的“负载平衡”,避免 fallback 时过度请求某个服务导致 IP 被 Ban。
</p>
<p>原文地址:https://mp.weixin.qq.com/s/l0qpYec1eTRUyDyADFgR6Q</p>
頁:
[1]