python - 以编程方式发现公共(public) IP

标签 python ip-address tcp

我在路由器后面,我需要一个简单的命令来发现我的公共(public) ip(而不是在谷歌上搜索我的 ip 并单击一个结果)

是否有任何标准协议(protocol)?听说过 STUN 但不知道怎么用?

附:我打算写一个简短的python脚本来做它

最佳答案

这可能是最简单的方法。解析以下命令的输出:

  1. 运行 traceroute 以查找距离您的计算机不到 3 跳的路由器。
  2. 使用选项运行 ping 以记录源路由并解析输出。记录路由中的第一个 IP 地址是您的公共(public)地址。

例如,我在一台 Windows 机器上,但同样的想法也应该适用于 unix。

> tracert -d www.yahoo.com

Tracing route to www-real.wa1.b.yahoo.com [69.147.76.15]
over a maximum of 30 hops:

  1    <1 ms    <1 ms    <1 ms  192.168.14.203
  2     *        *        *     Request timed out.
  3     8 ms     8 ms     9 ms  68.85.228.121
  4     8 ms     8 ms     9 ms  68.86.165.234
  5    10 ms     9 ms     9 ms  68.86.165.237
  6    11 ms    10 ms    10 ms  68.86.165.242

68.85.228.121 是 Comcast(我的提供商)路由器。我们可以ping通:

> ping -r 9 68.85.228.121 -n 1

Pinging 68.85.228.121 with 32 bytes of data:

Reply from 68.85.228.121: bytes=32 time=10ms TTL=253
    Route: 66.176.38.51 ->
           68.85.228.121 ->
           68.85.228.121 ->
           192.168.14.203

瞧! 66.176.38.51 是我的公共(public) IP。

执行此操作的 Python 代码(希望适用于 py2 或 py3):

#!/usr/bin/env python

def natIpAddr():
  # Find next visible host out from us to the internet
  hostList = []
  resp, rc = execute("tracert -w 100 -h 3 -d 8.8.8.8") # Remove '-w 100 -h d' if this fails

  for ln in resp.split('\n'):
    if len(ln)>0 and ln[-1]=='\r': ln = ln[:-1]  # Remove trailing CR
    if len(ln)==0: continue
    tok = ln.strip().split(' ')[-1].split('.') # Does last token look like a dotted IP address?
    if len(tok)!=4: continue
    hostList.append('.'.join(tok))
    if len(hostList)>1: break  # If we found a second host, bail
    
  if len(hostList)<2:
    print("!!tracert didn't work, try removing '-w 100 -h 3' options")
    # Those options were to speed up tracert results

  else:
    resp, rc = execute("ping -r 9 "+hostList[1]+" -n 1")
    ii = resp.find("Route: ")
    if ii>0: return resp[ii+7:].split(' ')[0]
  return none     


def execute(cmd, showErr=True, returnStr=True):
  import subprocess
  if type(cmd)==str:
    cmd = cmd.split(' ')
  # Remove ' ' tokens caused by multiple spaces in str             
  cmd = [xx for xx in cmd if xx!='']
  proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  out, err = proc.communicate()
  if type(out)==bytes:  # Needed for python 3 (stupid python)
    out = out.decode()
    try:
      err = err.decode()
    except Exception as ex: 
      err = "!!--"+str(type(ex))+"--!!"
  
  if showErr and len(err)>0:
    out += err
  if returnStr and str(type(out))=="<type 'unicode'>":
    # Trying to make 'out' be an ASCII string whether in py2 or py3, sigh.
    out = out.encode()  # Convert UNICODE (u'xxx') to string
  return out, proc.returncode


if __name__ == "__main__":
  print("(This could take 30 sec)")
  print(natIpAddr())

从命令行(在 Windows 上)或 python 程序中使用它:

import natIpAddr
myip = natIpAddr.natIpAddr()
print(myip)

关于python - 以编程方式发现公共(public) IP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/613471/

相关文章:

python如何内存一个方法

c# - TCP 实时多人游戏

tcp - 允许 golang 通过 Windows 防火墙进行测试

python - 对二维数组使用 searchsorted

python - 解析时意外的 EOF(解析字典)

python - 如何强制zlib解压超过X字节?

java - 如何以编程方式获取通过 Wifi 连接到交换机网络的其他设备的 IP 地址?

c# - 如何在 ASP.NET Core Web API 项目中允许使用 IP 地址进行 CORS?

.net - 如何在 WCF 中获取 netTcpBinding 调用的源 IP?

java - 是否可以将换行符写入套接字的 OutputStream?