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

Какой самый надежный скрипт для возврата IP-адреса реальных локальных ссылок Ethernet

Для некоторых сценариев туннелирования и привязки мне нужно найти (любой) локальный (без обратной связи) фактический интерфейс связи Ethernet и его IP-адрес.

Заметка это среда разработки - на моем ноутбуке с Linux - и эта конфигурация является динамической (может быть Wi-Fi, Ethernet и т. д.)

Заметка У меня работает множество подсистем docker и kubernetes, и, следовательно, есть много мостов, виртуальных интерфейсов и т. Д.

Вот что у меня есть на данный момент:

nmcli может дать мне устройства Wi-Fi:

nmcli d  | grep wifi | cut -d ' ' -f 1

(Но не аппаратный локальный Ethernet, так как тип, сообщаемый nmcli для некоторых виртуальных интерфейсов, также является ethernet)

От этого я мог (а) увернуться через какой-то хрупкий JQ

ip -br -j a show dev $DEV | jq -r .[1].addr_info[0].local

срочно

или, xkcd: // 208 мой путь к успеху?

ip -br a show dev $DEV | perl -nle 'print $1 if $_ =~ /.+ ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/'

Соображения:

Достаточно недавно (~ Ноя 2017) iproute2 инструменты обеспечивают -j[son] формат вывода, как вы уже тестировали. Вместе с -d[etails] вариант, в выводе, предназначенном для анализа, доступно много информации.

Похоже, что настоящие интерфейсы не отображают "linkinfo"объект (и связанный "info_kind" ключ, который является типом интерфейса: мост, vethи т. д. Точно так же без вывода JSON у этих интерфейсов нет третьей строки, которая есть у всех остальных виртуальных интерфейсов (хорошо, кроме loopback), которые начинаются со своего типа: мост и т.д.). Так что просто тестирование на "link_type": "ether" и отсутствие "linkinfo" должны сохранять только реальные интерфейсы Ethernet (частью которых являются интерфейсы Wi-Fi). Конечно, есть ограничения: если вы создадите mac80211_hwsim устройство, скорее всего, оно будет выглядеть реальным, поскольку оно имитирует устройство (а не просто интерфейс).

Итак, используя специализированный инструмент обработки JSON, который вы уже упоминали в своем вопросе: jq (читая его jq Руководство страницы было достаточно, чтобы сформулировать этот общий ответ), я написал следующее:

ip -details -json address show | \
    jq --join-output '.[] |
        if ."link_type" == "ether" and ."linkinfo" == null and (."addr_info" | length) > 0 then
            ."ifname" ,
            (."addr_info"[]|
                if ."family" == "inet" or ."family" == "inet6" then
                    " " + ."local"
                else
                    empty
                end), "\n"
        else
            empty
        end'

пример вывода (отредактировано):

 eth0 192.168.2.2 2001:db8:dead:beef:3116:312b:e620:3596 2001:db8:dead:beef:123:4567:89ab:cdef fe80::123:4567:89ab:cdef 
 wlan0 192.168.3.2 2001:db8:dead:bee5:dfa:a10b:df26:ef3e 2001:db8:dead:bee5:cdef:89ab:4567:123 fe80::cdef:89ab:4567:123 

Ноты

  • Если ты хочешь сохранить veth интерфейсы (иначе контейнеры, вероятно, никогда ничего не покажут) вы можете заменить ."linkinfo" == null с участием (."linkinfo" == null or ."linkinfo"."info_kind" == "veth").
  • Чтобы визуально прочитать прямой вывод команды JSON, лучше использовать ip -details -pretty -json address show.

Я не могу найти переключатель в существующей служебной программе, который возвращает это.

Но оказывается, что файл /sys/class/net/<iface>/device кажется, существует, если это реальный аппаратный интерфейс. (Я уверен, что это может быть неправильное утверждение)

Вот фрагмент Python для регулярного вывода IP-адресов из настроенных интерфейсов с такими sysfs записи.

#!/usr/bin/env python3

import os
import re

for dev in os.listdir('/sys/class/net'):
    if os.path.isdir('/sys/class/net/' + dev + '/device'):
        try:
            print(re.search(' ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})', os.popen('ip -br a show dev ' + dev).read()).groups()[0])
        except:
            pass

[1] https://gist.github.com/robshep/5daea97bd9f438d69c3e23e3ad02c0bd

Начать с ifconfig Сказать ens3 это интерфейс. ip addr show ens3 покажет всю информацию для этого интерфейса. Затем выполните команду grep с помощью inet фильтровать ip-адреса. Я думаю, вы хотите отфильтровать ipv4 только тогда, выполните команду grep с inet\b еще inet6 для адреса ipv6. Чтобы распечатать поле ipaddress, выполните awk '{print $2}' который печатает вторую часть inet.

ip addr show ens3 | grep "inet\b" | awk '{print $2}' 

Теперь у вас есть адрес с маскировкой, если вы хотите отказаться от маскировки, включите cut -d/ -f1 который отбросит маскирующую часть.

ip addr show ens3 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1

Поместите его в сценарий bash и запускайте, когда вам это нужно.