Назад | Перейти на главную страницу

Как получить локальный 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: Было предложено вызвать connect () на сокете udp, а затем вызвать 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 в скрипт оболочки:

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

Теперь у меня есть файл auto.tmp, содержащий автоматически сгенерированный адрес:

10.1.46.122

Однострочный пакет 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]

Почему бы не что-то вроде этого:

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

FYI, ifconfig устарела. Вам следует начать использовать различные ip команды вместо того, что вы использовали ifconfig для ранее.