如何获取与默认网关关联的本地 IP 地址

如何获取与默认网关关联的本地 IP 地址

服务器上可能有多个网络接口,例如 lo、eth0、eth1

从路由表中,我知道 eth0 连接到默认网关。默认网关的地址例如是 192.168.1.1。而 eth0 的地址例如是 192.168.1.100。

如何获取地址“192.168.1.100”?任何方法都可以:Python、Shell、UNIX C API...

目前我能想到的办法只有一个:

  1. 执行命令“route”并获取最后一行(默认 192.168.1.1 0.0.0.0 ...)
  2. 执行命令“ifconfig”,获取地址列表(127.0.0.1,192.168.1.100,...)
  3. 查找与默认网关(192.168.1.1)位于同一子网的地址
  4. 然后我们得到地址192.168.1.100

还有其他更好的解决方案吗?

PS:有人建议我们可以在 udp 套接字上调用 connect(),然后调用 getsockname() 来获取本地地址。但是,这只在部分服务器上有效。

@EEAA

这是我的脚本:

route -n | awk '$1 == "0.0.0.0" { print $2 }' > gateway.tmp
ip -4 addr show | grep inet | awk '{ print $2 }' > addrs.tmp

第一行打印默认网关:

10.1.40.1

第二行打印接口地址列表(以 cidr 表示法):

127.0.0.1/8
10.1.46.122/21

然后我必须确定 10.1.40.1 属于哪个网络。因此我编写了一个 Python 脚本:

import sys

def ip_to_binary(ip):
    bytes = ip.split(".")
    a = int(bytes[0])
    b = int(bytes[1])
    c = int(bytes[2])
    d = int(bytes[3])
    return "{0:08b}{1:08b}{2:08b}{3:08b}".format(a, b, c, d)

def mask_to_binary(bits):
    return "1" * bits + "0" * (32 - bits)

def binary_and(a, b):
    if len(a) == len(b):
        result = ""
        for i in range(0, len(a)):
            if a[i] == "1" and b[i] == "1":
                result += "1"
            else:
                result += "0"
        return result
    return None

def ip_in_net(ip, net_cidr_notation):
    net_addr, bits = net_cidr_notation.split("/")
    bin_mask = mask_to_binary(int(bits))
    bin_net = ip_to_binary(net_addr)
    bin_ip = ip_to_binary(ip)

    if binary_and(bin_ip, bin_mask) == binary_and(bin_net, bin_mask):
        return True
    return False

# usage: python autoaddr.py gateway_file addrs_file
gateway = open(sys.argv[1]).readline().strip()
addrs = open(sys.argv[2]).readlines()

for addr in addrs:
    if ip_in_net(gateway, addr):
        print addr.split("/")[0]

为了避免额外的依赖,我没有使用 netaddr 和 ipaddress 之类的库。最后,我必须将 Python 脚本添加到 Shell 脚本中:

python autoaddr.py gateway.tmp addrs.tmp > auto.tmp
rm -f gateway.tmp
rm -f addrs.tmp

现在我有一个文件 auto.tmp,其中包含自动生成的地址:

10.1.46.122

答案1

一行 bash 命令即可获取你机器的“默认 IP 地址”:

ip -o route get 1.1.1.1 | cut -d " " -f 7

如果你在 Python 3 中需要它:

def get_default_ip():
    output = subprocess.check_output(["ip", "-o", "route", "get", "1.1.1.1"],
                                     universal_newlines=True)
    return output.split(" ")[6]

答案2

为什么不像这样:

$ ip -4 addr show eth0 | grep inet | awk '{ print $2 }'
192.168.1.100/24

仅供参考,ifconfig已弃用。您应该开始使用各种ip命令来代替ifconfig以前使用的命令。

相关内容