web-dev-qa-db-fra.com

Comment déterminer toutes mes adresses IP lorsque j'ai plusieurs NIC?

J'ai plusieurs cartes d'interface réseau sur mon ordinateur, chacune avec sa propre adresse IP.

Lorsque j'utilise gethostbyname(gethostname()) du module socket de Python (intégré), il n'en renvoie qu'un. Comment puis-je obtenir les autres?

30
Wilson F

Utilisez le module netifaces . La mise en réseau étant complexe, utiliser des netifaces peut être un peu délicat, mais voici comment faire ce que vous voulez:

>>> import netifaces
>>> netifaces.interfaces()
['lo', 'eth0']
>>> netifaces.ifaddresses('eth0')
{17: [{'broadcast': 'ff:ff:ff:ff:ff:ff', 'addr': '00:11:2f:32:63:45'}], 2: [{'broadcast': '10.0.0.255', 'netmask': '255.255.255.0', 'addr': '10.0.0.2'}], 10: [{'netmask': 'ffff:ffff:ffff:ffff::', 'addr': 'fe80::211:2fff:fe32:6345%eth0'}]}
>>> for interface in netifaces.interfaces():
...   print netifaces.ifaddresses(interface)[netifaces.AF_INET]
...
[{'peer': '127.0.0.1', 'netmask': '255.0.0.0', 'addr': '127.0.0.1'}]
[{'broadcast': '10.0.0.255', 'netmask': '255.255.255.0', 'addr': '10.0.0.2'}]
>>> for interface in netifaces.interfaces():
...   for link in netifaces.ifaddresses(interface)[netifaces.AF_INET]:
...     print link['addr']
...
127.0.0.1
10.0.0.2

Cela peut être rendu un peu plus lisible comme ceci:

from netifaces import interfaces, ifaddresses, AF_INET

def ip4_addresses():
    ip_list = []
    for interface in interfaces():
        for link in ifaddresses(interface)[AF_INET]:
            ip_list.append(link['addr'])
    return ip_list

Si vous voulez des adresses IPv6, utilisez AF_INET6 au lieu de AF_INET. Si vous vous demandez pourquoi netifaces utilise des listes et des dictionnaires partout, c'est parce qu'un même ordinateur peut avoir plusieurs cartes d'interface réseau et que chaque NIC peut avoir plusieurs adresses et que chaque adresse possède son propre ensemble d'options.

43
Harley Holcombe
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
10
Nakilon

Toutes les adresses en une seule ligne à l'aide du module netifaces:

[netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr'] for iface in netifaces.interfaces() if netifaces.AF_INET in netifaces.ifaddresses(iface)]
9
Elemag

Juste pour être complet, une autre option serait d’utiliser psutil

tldr;

import socket
import psutil

def get_ip_addresses(family):
    for interface, snics in psutil.net_if_addrs().items():
        for snic in snics:
            if snic.family == family:
                yield (interface, snic.address)

ipv4s = list(get_ip_addresses(socket.AF_INET))
ipv6s = list(get_ip_addresses(socket.AF_INET6))

Explication

La fonction dont vous avez besoin est net_if_addrs . C'est à dire.:

import psutil
psutil.net_if_addrs()

Ce qui donne quelque chose comme ça (Python 3):

{'br-ae4880aa80cf': [snic(family=<AddressFamily.AF_INET: 2>, address='172.18.0.1', netmask='255.255.0.0', broadcast='172.18.0.1', ptp=None),
                     snic(family=<AddressFamily.AF_PACKET: 17>, address='02:42:e5:ae:39:94', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'docker0': [snic(family=<AddressFamily.AF_INET: 2>, address='172.17.0.1', netmask='255.255.0.0', broadcast='172.17.0.1', ptp=None),
             snic(family=<AddressFamily.AF_PACKET: 17>, address='02:42:38:d2:4d:77', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'eno1': [snic(family=<AddressFamily.AF_PACKET: 17>, address='54:be:f7:0b:cf:a9', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast=None, ptp=None),
        snic(family=<AddressFamily.AF_PACKET: 17>, address='00:00:00:00:00:00', netmask=None, broadcast=None, ptp=None)],
 'wlp2s0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.4', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
            snic(family=<AddressFamily.AF_PACKET: 17>, address='00:21:27:ee:d6:03', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}

(Python 2):

{'br-ae4880aa80cf': [snic(family=2, address='172.18.0.1', netmask='255.255.0.0', broadcast='172.18.0.1', ptp=None),
                     snic(family=17, address='02:42:e5:ae:39:94', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'docker0': [snic(family=2, address='172.17.0.1', netmask='255.255.0.0', broadcast='172.17.0.1', ptp=None),
             snic(family=17, address='02:42:38:d2:4d:77', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'eno1': [snic(family=17, address='54:be:f7:0b:cf:a9', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],
 'lo': [snic(family=2, address='127.0.0.1', netmask='255.0.0.0', broadcast=None, ptp=None),
        snic(family=17, address='00:00:00:00:00:00', netmask=None, broadcast=None, ptp=None)],
 'wlp2s0': [snic(family=2, address='192.168.1.4', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
            snic(family=17, address='00:21:27:ee:d6:03', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}

Note : Etant donné que vous pouvez avoir plus d'une adresse de la même famille associée à chaque interface, les valeurs dict sont des listes.

Chaque snic est un namedtuple qui comprend 5 champs:

  • family: la famille d'adresses, soit AF_INET, AF_INET6 ou psutil.AF_LINK, qui fait référence à une adresse MAC.
  • address: l'adresse principale NIC (toujours définie).
  • netmask: l'adresse du masque de réseau (peut être None).
  • broadcast: l'adresse de diffusion (peut être Aucun).
  • ptp: signifie “point à point”; c'est l'adresse de destination sur une interface point à point (généralement un VPN). broadcast et ptp s’excluent mutuellement (peut être None).
7
pmav99

https://docs.python.org/3.4/library/socket.html#socket.if_nameindex

socket.if_nameindex ()

Renvoie une liste de tuples d'informations d'interface réseau (index int, name string). OSError si l'appel système échoue.

Disponibilité: Unix.

Nouveau dans la version 3.3.


fait ce code qui est exécutable sur Python 3.4, UNIX/Linux

#!/env/python3.4
import socket
import fcntl
import struct

def active_nic_addresses():
    """
    Return a list of IPv4 addresses that are active on the computer.
    """

    addresses = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1]

    return addresses

def get_ip_address( NICname ):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', NICname[:15].encode("UTF-8"))
    )[20:24])


def nic_info():
    """
    Return a list with tuples containing NIC and IPv4
    """
    nic = []

    for ix in socket.if_nameindex():
        name = ix[1]
        ip = get_ip_address( name )

        nic.append( (name, ip) )

    return nic

if __== "__main__":

    print( active_nic_addresses() )
    print( nic_info() )

Imprimera quelque chose comme:

['192.168.0.2']
[('lo', '127.0.0.1'), ('enp3s0', '192.168.0.2')]
2
The Demz

Voici une routine pour rechercher toutes les interfaces IPv4 et IPv6. Comme l'a déjà souligné un autre poster, socket.gethostbyname_ex () ne fonctionne pas pour IPv6 et la documentation Python recommande une utilisation socket.getaddressinfo () .

Cette routine ajoute l'interface de rappel IPv4 (127.0.0.1). S'il existe des interfaces IPv6, elle ajoute également l'interface de rappel IPv6 (:: 1). Socket.getaddrinfo () me donnera un ou les deux, mais seulement si je n'ai pas d'autre interface disponible.

Pour mes besoins, je voulais essayer d'ouvrir un socket UDP sur un port spécifié de chacune de mes interfaces disponibles. C'est pourquoi le code contient "port" et socket.SOCK_DGRAM. Il est prudent de changer ceux-ci, par exemple si vous n'avez pas de port en tête.

addrinfo_ipv4 = socket.getaddrinfo(hostname,port,socket.AF_INET,socket.SOCK_DGRAM)
addrinfo_ipv6 = []
try:
    addrinfo_ipv6 = socket.getaddrinfo(hostname,port,socket.AF_INET6,socket.SOCK_DGRAM)
except socket.gaierror:
    pass
addrinfo = [(f,t,a) for f,t,p,cn,a in addrinfo_ipv4+addrinfo_ipv6]
addrinfo_local = [(socket.AF_INET,socket.SOCK_DGRAM,('127.0.0.1',port))]
if addrinfo_ipv6: 
    addrinfo_local.append( (socket.AF_INET6,socket.SOCK_DGRAM,('::1',port)) )
[addrinfo.append(ai) for ai in addrinfo_local if ai not in addrinfo]
1
DamonJW

C'est linux seulement, mais il y a une recette très simple ici http://code.activestate.com/recipes/439094/

Il utilise probablement un code similaire au paquet netifaces mentionné dans une autre réponse (mais la version actuelle est liée ici)

Socket.getaddrinfo () ne renvoie pas l'adresse IP associée au périphérique. Si votre fichier hosts contient une ligne avec "127.0.1.1 yourhost.example.com yourhost", qui est une configuration courante, getaddrinfo ne renverra que 127.0.1.1.

1
JimB

Cet extrait donnera une liste de toutes les adresses IPV4 disponibles dans le système.

import itertools
from netifaces import interfaces, ifaddresses, AF_INET

links = filter(None, (ifaddresses(x).get(AF_INET) for x in interfaces()))
links = itertools.chain(*links)
ip_addresses = [x['addr'] for x in links]
1
Sandeep

Vous pouvez le faire assez facilement comme ceci:

import netifaces

for interface in netifaces.interfaces():
    print netifaces.ifaddresses(interface)

Pour plus d'informations, vous pouvez consulter la documentation netifaces .

0
Tlili Marwen

Comme ce fil l'indique, il existe de nombreuses façons d'obtenir le même résultat. Je suggère d'utiliser le filtre de famille intégré dans getaddrinfo() et d'analyser le tuple standardisé comme suit:

from socket import getaddrinfo, AF_INET, gethostname

for ip in getaddrinfo(Host=gethostname(), port=None, family=AF_INET):   
    print(ip[4][0])

Exemple de sortie:

192.168.55.1
192.168.170.234
0
chjortlund

Je pense que la réponse de @Harley Holcombe est réalisable, mais si vous avez des cartes réseau virtuelles sans adresse IP, cela entraînera une erreur. c'est donc j'ai modifié:

def get_lan_ip():
for interface in interfaces():
    try:
        for link in ifaddresses(interface)[AF_INET]:
            if str(link['addr']).startswith("172."):
                return str(link['addr'])
    except:
        pass

cela ne fera que retourner votre lan ipv4

0
yongdi

Vous devez obtenir directement toutes les adresses IP configurées IP, par exemple en exécutant ifconfig et en analysant sa sortie (il est également possible de faire ce que ifconfig fait directement dans Python , voir comment cela se fait dans C ). Si vous voulez des noms d'hôte, utilisez gethostbyaddr.

0
Martin v. Löwis