Obtener direcciones de interfaz de red local usando solo proc?
¿Cómo puedo obtener las direcciones (IPv4) para todas las interfaces de red usando solo proc? Después de una extensa investigación he descubierto lo siguiente: {[13]]}
-
ifconfig
hace uso deSIOCGIFADDR
, que requiere sockets abiertos y conocimiento previo de todos los nombres de interfaz. Tampoco está documentado en ninguna página de manual en Linux. -
proc
contiene/proc/net/dev
, pero esta es una lista de estadísticas de interfaz. -
proc
contiene/proc/net/if_inet6
, que es exactamente lo que solo se necesita IPv6. - Generalmente las interfaces son fáciles de encontrar en
proc
, pero las direcciones reales son muy raramente usadas excepto cuando explícitamente forman parte de alguna conexión. - Hay una llamada al sistema llamada
getifaddrs
, que es en gran medida una función" mágica " que esperarías ver en Windows. También está implementado en BSD. Sin embargo, no está muy orientado al texto, lo que hace que sea difícil de usar desde idiomas que no son C.
8 answers
No hay un análogo IPv4 de/proc/net / if_inet6
Ifconfig hace:
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)
ioctl(fd, SIOCGIFCONF, ...)
Obtendrás algo como esto:
ioctl(4, SIOCGIFCONF, {120, {{"lo", {AF_INET, inet_addr("127.0.0.1")}}, {"eth0", {AF_INET, inet_addr("10.6.23.69")}}, {"tun0", {AF_INET, inet_addr("10.253.10.151")}}}})
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-12 12:18:52
Puede encontrar la salida de ip addr show
más fácil de analizar que la salida de otras herramientas:
$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:24:1d:ce:47:05 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.121/24 brd 192.168.0.255 scope global eth0
inet6 fe80::224:1dff:fece:4705/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
link/ether 00:24:1d:ce:35:d5 brd ff:ff:ff:ff:ff:ff
4: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN
link/ether 92:e3:6c:08:1f:af brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
inet6 fe80::90e3:6cff:fe08:1faf/64 scope link
valid_lft forever preferred_lft forever
Otra opción es el archivo /proc/net/tcp
. Muestra todas las sesiones TCP actualmente abiertas, que es diferente de lo que pidió, pero podría ser lo suficientemente Bueno.
$ cat tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13536 1 ffff88019f0a1380 300 0 0 2 -1
1: 00000000:1355 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 19877854 1 ffff880016e69380 300 0 0 2 -1
2: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13633 1 ffff88019f0a1a00 300 0 0 2 -1
3: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8971 1 ffff88019f0a0000 300 0 0 2 -1
4: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 12952880 1 ffff880030e30680 300 0 0 2 -1
5: 00000000:0539 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 14332 1 ffff88019f0a2080 300 0 0 2 -1
6: 00000000:C000 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 14334 1 ffff88019f0a2700 300 0 0 2 -1
7: 0100007F:0A44 00000000:0000 0A 00000000:00000000 00:00000000 00000000 119 0 51794804 1 ffff880016e6a700 300 0 0 2 -1
8: 7900A8C0:B094 53D50E48:01BB 01 00000000:00000000 00:00000000 00000000 1000 0 64877487 1 ffff880100502080 23 4 16 4 -1
9: 7900A8C0:9576 537F7D4A:01BB 06 00000000:00000000 03:00000E5D 00000000 0 0 0 3 ffff880100c84600
10: 7900A8C0:CC84 0CC181AE:01BB 01 00000000:00000000 00:00000000 00000000 1000 0 61775908 1 ffff880198715480 35 4 11 4 -1
$ irb
irb(main):001:0> [0x79, 0x00, 0xa8, 0xc0]
=> [121, 0, 168, 192]
Mi IP es 192.168.0.121
; tenga en cuenta la aritmética divertida para que salga bien. :)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-12 08:05:24
/proc/net/fib_trie
sostiene la topografía de la red
Para imprimir simplemente las direcciones de todos los adaptadores:
$ awk '/32 host/ { print f } {f=$2}' <<< "$(</proc/net/fib_trie)"
127.0.0.1
192.168.0.5
192.168.1.14
Para determinar el adaptador de esas direcciones (a) consulte las redes de destino de los adaptadores de /proc/net/route
, (b) haga coincidir esas redes con las de /proc/net/fib_trie
y (c) imprima las direcciones de host /32 correspondientes listadas en esas redes.
De nuevo no python
desafortunadamente, pero un enfoque bastante awky bash
:
#!/bin/bash
ft_local=$(awk '$1=="Local:" {flag=1} flag' <<< "$(</proc/net/fib_trie)")
for IF in $(ls /sys/class/net/); do
networks=$(awk '$1=="'$IF'" && $3=="00000000" && $8!="FFFFFFFF" {printf $2 $8 "\n"}' <<< "$(</proc/net/route)" )
for net_hex in $networks; do
net_dec=$(awk '{gsub(/../, "0x& "); printf "%d.%d.%d.%d\n", $4, $3, $2, $1}' <<< $net_hex)
mask_dec=$(awk '{gsub(/../, "0x& "); printf "%d.%d.%d.%d\n", $8, $7, $6, $5}' <<< $net_hex)
awk '/'$net_dec'/{flag=1} /32 host/{flag=0} flag {a=$2} END {print "'$IF':\t" a "\n\t'$mask_dec'\n"}' <<< "$ft_local"
done
done
exit 0
Salida:
eth0: 192.168.0.5
255.255.255.0
lo: 127.0.0.1
255.0.0.0
wlan0: 192.168.1.14
255.255.255.0
Conocido limitación:
Este enfoque no funciona de forma fiable para direcciones de host que comparten la red con otras direcciones de host. Esta pérdida de unicidad de la red hace imposible determinar la dirección de host correcta de fib_trie, ya que el orden de esas direcciones no coincide necesariamente con el orden de las redes de ruta.
Dicho esto, no estoy seguro de por qué querría varias direcciones de host pertenecientes a la misma red en primer lugar. Por lo tanto, en la mayoría de los casos de uso, este enfoque debe funciona bien.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-07 22:11:21
Mi solución para recuperar la configuración de red IPv4, usando /proc
solo:
Desafortunadamente, esto es bash (bash solo y sin ninguna bifurcación), no python. Pero espero que esto sea legible:
#!/bin/bash
# ip functions that set variables instead of returning to STDOUT
hexToInt() {
printf -v $1 "%d\n" 0x${2:6:2}${2:4:2}${2:2:2}${2:0:2}
}
intToIp() {
local var=$1 iIp
shift
for iIp ;do
printf -v $var "%s %s.%s.%s.%s" "${!var}" $(($iIp>>24)) \
$(($iIp>>16&255)) $(($iIp>>8&255)) $(($iIp&255))
done
}
maskLen() {
local i
for ((i=0; i<32 && ( 1 & $2 >> (31-i) ) ;i++));do :;done
printf -v $1 "%d" $i
}
# The main loop.
while read -a rtLine ;do
if [ ${rtLine[2]} == "00000000" ] && [ ${rtLine[7]} != "00000000" ] ;then
hexToInt netInt ${rtLine[1]}
hexToInt maskInt ${rtLine[7]}
if [ $((netInt&maskInt)) == $netInt ] ;then
for procConnList in /proc/net/{tcp,udp} ;do
while IFS=': \t\n' read -a conLine ;do
if [[ ${conLine[1]} =~ ^[0-9a-fA-F]*$ ]] ;then
hexToInt ipInt ${conLine[1]}
[ $((ipInt&maskInt)) == $netInt ] && break 3
fi
done < $procConnList
done
fi
fi
done < /proc/net/route
# And finaly the printout of what's found
maskLen maskBits $maskInt
intToIp addrLine $ipInt $netInt $maskInt
printf -v outForm '%-12s: %%s\\n' Interface Address Network Netmask Masklen
printf "$outForm" $rtLine $addrLine $maskBits\ bits
Hay una muestra de salida:
Interface : eth0
Address : 192.168.1.32
Network : 192.168.1.0
Netmask : 255.255.255.0
Masklen : 24 bits
Explicación:
Utilizo el valor entero de IPV4 para comprobar IP & MASK == NETWORK
.
Leo primero /proc/net/route
para encontrar configuraciones de enrutamiento, buscando rutas accesibles sin ninguna gateway (gw==000000
).
Para tal ruta, busco en todas las conexiones (TCP, que UDP si no se encuentra en TCP) para la conexión usando esta ruta, el primer punto final es mi dirección de host.
Nota: Esto no funcionará con conexiones PPP
Nota2: Esto no funcionará en un host totalmente silencioso sin ninguna conexión de red abierta.
Usted podría hacer algo como echo -ne '' | nc -q 0 -w 1 8.8.8.8 80 & sleep .2 && ./retrieveIp.sh
para asegurarse de que algo se encuentra en /proc/net/tcp
.
Nota3, 2016-09.23: New bash versión use la sintaxis >(command)
para multiple inline pipe
feature . Esto implica un error en la línea 18: un espacio debe estar presente entre >
y (
!!
Nueva versión con gateway
Hay un pequeño parche: Una vez que cree un archivo llamado getIPv4.sh
copiando el script anterior, podría pegar lo siguiente en el comando: patch -p0
--- getIPv4.sh
+++ getIPv4.sh
@@ -35,13 +35,16 @@
done < $procConnList
done
fi
+ elif [ ${rtLine[1]} == "00000000" ] && [ ${rtLine[7]} == "00000000" ] ;then
+ hexToInt netGw ${rtLine[2]}
fi
done < /proc/net/route
# And finaly the printout of what's found
maskLen maskBits $maskInt
-intToIp addrLine $ipInt $netInt $maskInt
-printf -v outForm '%-12s: %%s\\n' Interface Address Network Netmask Masklen
+intToIp addrLine $ipInt $netInt $netGw $maskInt
+printf -v outForm '%-12s: %%s\\n' \
+ Interface Address Network Gateway Netmask Masklen
printf "$outForm" $rtLine $addrLine $maskBits\ bits
End con Ctrld, esto puede de salida:
patching file getIPv4.sh
Y tal vez
Hunk #1 succeeded at 35 with fuzz 2.
Entonces vuelva a ejecutar su script:
getIPv4.sh
Interface : eth0
Address : 192.168.1.32
Network : 192.168.1.0
Gateway : 192.168.1.1
Netmask : 255.255.255.0
Masklen : 24 bits
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-15 21:05:30
ip addr show dev eth0 | grep "inet " | cut -d ' ' -f 6 | cut -f 1 -d '/'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-28 02:38:56
Cat/proc/net / tcp
Obtener la segunda columna, con el título "local_address", por ejemplo,"CF00A8C0:0203"
La parte después de ":" es un número de puerto.
Del resto use los dos últimos (C0) como un número hexadecimal, por ejemplo, C0 es 192, que es el comienzo de la dirección en este ejemplo.
Tomé lo siguiente en mis notas hace un tiempo, desde algún punto inteligente en la red:
La dirección IP se muestra como un número hexadecimal de cuatro bytes little-endian; es decir, el menor el byte significativo aparece primero, por lo tanto, deberá invertir el orden de los bytes para convertirlo en una dirección IP.
El número de puerto es un número hexadecimal simple de dos bytes.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-09 11:15:52
La suya es una fantasía que encontré en algún lugar de Internet. minorly lo arregló para que encajara y emitiera correctamente los dispositivos tun (vpn).
#!/usr/bin/python
from socket import AF_INET, AF_INET6, inet_ntop
from ctypes import (
Structure, Union, POINTER,
pointer, get_errno, cast,
c_ushort, c_byte, c_void_p, c_char_p, c_uint, c_int, c_uint16, c_uint32
)
import ctypes.util
import ctypes
class struct_sockaddr(Structure):
_fields_ = [
('sa_family', c_ushort),
('sa_data', c_byte * 14),]
class struct_sockaddr_in(Structure):
_fields_ = [
('sin_family', c_ushort),
('sin_port', c_uint16),
('sin_addr', c_byte * 4)]
class struct_sockaddr_in6(Structure):
_fields_ = [
('sin6_family', c_ushort),
('sin6_port', c_uint16),
('sin6_flowinfo', c_uint32),
('sin6_addr', c_byte * 16),
('sin6_scope_id', c_uint32)]
class union_ifa_ifu(Union):
_fields_ = [
('ifu_broadaddr', POINTER(struct_sockaddr)),
('ifu_dstaddr', POINTER(struct_sockaddr)),]
class struct_ifaddrs(Structure):
pass
struct_ifaddrs._fields_ = [
('ifa_next', POINTER(struct_ifaddrs)),
('ifa_name', c_char_p),
('ifa_flags', c_uint),
('ifa_addr', POINTER(struct_sockaddr)),
('ifa_netmask', POINTER(struct_sockaddr)),
('ifa_ifu', union_ifa_ifu),
('ifa_data', c_void_p),]
libc = ctypes.CDLL(ctypes.util.find_library('c'))
def ifap_iter(ifap):
ifa = ifap.contents
while True:
yield ifa
if not ifa.ifa_next:
break
ifa = ifa.ifa_next.contents
def getfamaddr(sa):
family = sa.sa_family
addr = None
if family == AF_INET:
sa = cast(pointer(sa), POINTER(struct_sockaddr_in)).contents
addr = inet_ntop(family, sa.sin_addr)
elif family == AF_INET6:
sa = cast(pointer(sa), POINTER(struct_sockaddr_in6)).contents
addr = inet_ntop(family, sa.sin6_addr)
return family, addr
class NetworkInterface(object):
def __init__(self, name):
self.name = name
self.index = libc.if_nametoindex(name)
self.addresses = {}
def __str__(self):
return "%s [index=%d, IPv4=%s, IPv6=%s]" % (
self.name, self.index,
self.addresses.get(AF_INET),
self.addresses.get(AF_INET6))
def get_network_interfaces():
ifap = POINTER(struct_ifaddrs)()
result = libc.getifaddrs(pointer(ifap))
if result != 0:
raise OSError(get_errno())
del result
try:
retval = {}
for ifa in ifap_iter(ifap):
name = ifa.ifa_name
i = retval.get(name)
if not i:
i = retval[name] = NetworkInterface(name)
try:
family, addr = getfamaddr(ifa.ifa_addr.contents)
except ValueError:
family, addr = None, None
if addr:
i.addresses[family] = addr
return retval.values()
finally:
libc.freeifaddrs(ifap)
if __name__ == '__main__':
print [str(ni) for ni in get_network_interfaces()]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-22 14:29:05
Es bass-ackwards y probablemente estoy olvidando un caso de esquina, pero si nos fijamos en /proc/1/net/route, que tiene su tabla de enrutamiento. Si selecciona líneas para las que la puerta de enlace es 0.0.0.0, la primera columna es la interfaz y la segunda columna es la representación hexadecimal de su dirección IP, en orden de bytes de red (y la tercera columna es la ip de la puerta de enlace sobre la que desea filtrar).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-07 00:05:00