Get local network interface addresses using only proc?
Solution 1
There is no IPv4 analog of /proc/net/if_inet6
ifconfig does:
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)
ioctl(fd, SIOCGIFCONF, ...)
You'll get something like this:
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")}}}})
Solution 2
/proc/net/fib_trie
holds the network topography
To simply print the addresses of all adapters:
$ awk '/32 host/ { print f } {f=$2}' <<< "$(</proc/net/fib_trie)"
127.0.0.1
192.168.0.5
192.168.1.14
To determine the adapter of those addresses (a) consult the adapters' destination networks from /proc/net/route
, (b) match those networks with the ones of /proc/net/fib_trie
and (c) print the corresponding /32 host addresses listed under those networks.
Again no python
unfortunately, but a quite awky bash
approach:
#!/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
output:
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
Known limitation:
This approach does not work reliably for host addresses that share the network with other host addresses. This loss of network uniqueness makes it impossible to determine the correct host address from fib_trie as the order of those addresses does not necessarily match the order of networks of route.
Having said that, I'm not sure why you would want multiple host addresses belonging to the same network in first place. So in most use cases this approach should work just fine.
Solution 3
You may find the output of ip addr show
easier to parse than output from other tools:
$ 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
Another option is the file /proc/net/tcp
. It shows all currently-open TCP sessions, which is different than what you asked for, but might be Good Enough.
$ 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]
My IP is 192.168.0.121
; note the funny arithmetic to make it come out right. :)
Solution 4
My solution to retrieve IPv4 network config, using /proc
only:
Unfortunately, this is bash (bash only and without any fork), not python. But I hope this will be readable:
#!/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
There is a sample of output:
Interface : eth0
Address : 192.168.1.32
Network : 192.168.1.0
Netmask : 255.255.255.0
Masklen : 24 bits
Explanation:
I use integer value of IPV4 in order to check IP & MASK == NETWORK
.
I read first /proc/net/route
to find routing configurations, searching for routes reachable without any gateway (gw==000000
).
For such a route, I search in all connections (TCP, than UDP if not found in TCP) for connection using this route, the first end point is my host address.
Nota: This won't work with PPP connections
Nota2: This won't work on a totally quiet host without any opened network connection.
You could do something like echo -ne '' | nc -q 0 -w 1 8.8.8.8 80 & sleep .2 && ./retrieveIp.sh
for ensuring that something where found in /proc/net/tcp
.
Nota3, 2016-09.23: New bash version use >(command)
syntax for multiple inline pipe
feature. This implie a bug at line 18: a space must be present between >
and (
!!
New version with gateway
There is a little patch: Once you create a file called getIPv4.sh
by copying previous script, you could paste the following to the command: 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 with Ctrld, this may output:
patching file getIPv4.sh
And maybe
Hunk #1 succeeded at 35 with fuzz 2.
Then re-run your 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
Solution 5
ip addr show dev eth0 | grep "inet " | cut -d ' ' -f 6 | cut -f 1 -d '/'
Related videos on Youtube
Matt Joiner
About Me I like parsimonious code, with simple interfaces and excellent documentation. I'm not interested in enterprise, boiler-plate, or cookie-cutter nonsense. I oppose cruft and obfuscation. My favourite languages are Go, Python and C. I wish I was better at Haskell. Google+ GitHub Bitbucket Google code My favourite posts http://stackoverflow.com/questions/3609469/what-are-the-thread-limitations-when-working-on-linux-compared-to-processes-for/3705919#3705919 http://stackoverflow.com/questions/4352425/what-should-i-learn-first-before-heading-to-c/4352469#4352469 http://stackoverflow.com/questions/6167809/how-much-bad-can-be-done-using-register-variables-in-c/6168852#6168852 http://stackoverflow.com/questions/4141307/c-and-c-source-code-profiling-tools/4141345#4141345 http://stackoverflow.com/questions/3463207/how-big-can-a-malloc-be-in-c/3486163#3486163 http://stackoverflow.com/questions/4095637/memory-use-of-stl-data-structures-windows-vs-linux/4183178#4183178
Updated on July 14, 2021Comments
-
Matt Joiner almost 3 years
How can I obtain the (IPv4) addresses for all network interfaces using only proc? After some extensive investigation I've discovered the following:
-
ifconfig
makes use ofSIOCGIFADDR
, which requires open sockets and advance knowledge of all the interface names. It also isn't documented in any manual pages on Linux. -
proc
contains/proc/net/dev
, but this is a list of interface statistics. -
proc
contains/proc/net/if_inet6
, which is exactly what I need but for IPv6. - Generally interfaces are easy to find in
proc
, but actual addresses are very rarely used except where explicitly part of some connection. - There's a system call called
getifaddrs
, which is very much a "magical" function you'd expect to see in Windows. It's also implemented on BSD. However it's not very text-oriented, which makes it difficult to use from non-C languages.
-
Matt Joiner about 13 years@forest: Because it implies parsable text, dependence on modern Linux, and doesn't require spawning processes.
-
ʇsәɹoɈ about 13 yearsI see. Sadly, I don't know that the /proc data structures you'd need are guaranteed to remain consistent between operating systems or even kernel releases. (Someone please prove me wrong.) Meanwhile, the ifconfig and ip programs produce stable output, which is why I ended up choosing to parse it instead of turning to /proc. Here's an alternative that looks promising: pypi.python.org/pypi/dnet
-
F. Hauri - Give Up GitHub over 11 yearsDid you try
iproute2
suite?
-
-
Matt Joiner about 13 yearsHmm, ip(1) is nice. It'll be much better to fallback onto than ifconfig, thanks.
-
Matt Joiner about 13 yearsHow bizarre. Why do both
SIOCGIFCONF
andgetifaddrs
exist? -
amcnabb almost 12 yearsThe second column isn't the IP address but rather the network address, so this won't work, unfortunately.
-
SourceSeeker about 11 yearsThere's no need to do any of the
export
statements in your script. For integer comparisons, you should use the formif (( expr == num ))
instead ofif [ $((expr)) == $num ]
. For otherif
statements, you should use double square brackets instead of single. -
SourceSeeker about 11 years
export
isn't needed when yousource
this script, either. It would only be needed if the variables and functions were to be used in child processes of this script. Using the correct Bash form for comparisons simplifies the statements, makes their meaning more clear and provides additional functionality and robustness. -
F. Hauri - Give Up GitHub about 11 yearsWhy not simply:
printf "%d.%d.%d.%d\n" 0xc0 0xa8 0x00 0x79
(I've tested, this work under bash, dash, zsh, csh and ksh.) -
sarnold about 11 years@F.Hauri, the actual printing method for hex->decimal doesn't much matter. What does matter is that the
0x79 0x00..
is given in my abuse ofirb
in the same order as the last entries in/proc/net/tcp
. Reversing the bytes, as you've done, I think makes it harder to spot the data that you're looking for and how to fix it. Of course, if you're writing a portable script,printf(1)
is the way to go. :) But hereirb
is just used for illustration. Thanks :) -
RzR about 8 yearsLike : tail -n1 /proc/net/tcp 7: 1002000A:65F5 0202000A:DBEA 01 00000000:00000000 00:00000000 00000000 0 0 13951 3 de559e00 21 4 11 10 -1 printf "%d.%d.%d.%d\n" 0x10 0x02 0x00 0x0A 16.2.0.10
-
Pelle over 7 yearsSaved a 'grep' by adding more switches to ip:
ip -o -4 addr show dev eth0 | cut -d ' ' -f 7 | cut -f 1 -d '/'
-o for one-line, -4 to show ipv4 only -
F. Hauri - Give Up GitHub over 7 years@DennisWilliamson Did you notice that new
>(...)
bashism make this not work anymore... A space is to be added after>
! ... :-/ -
Maytas Monsereenusorn about 7 yearsHow do you match the ip address from fib_trie to the network interface name in /proc/net/route? Inspecting my /proc/net/route, I have multiple entries for the same network interface name. Furthermore, the ip address from fib_trie doesn't seem to match the 'destination' column, which is the IP converted from hex and reverse order, of ANY entries in the route table .
-
Tim Ludwinski almost 7 yearsThis file doesn't exist in CentOS 5.
-
xchange over 6 years@Maytas Monsereenusorn Both fib_trie & route have in common that they provide the NETWORK IP address. Generally this network is unique to the HOST IP address. Thus you can link the corresponding interface from route with the corresponding host IP address from fib_trie. You can have multiple host IPs for the same interface, but they should not belong to the same network (see limitation above as to why). Is it possible that you are including host routes when speaking of 'multiple entries for the same network interface name' in /proc/net/route? Those entries are not considered by the script.
-
Haqa about 6 yearsThis isn't helpful as the OP asked for a way using only the /proc filesystem!
-
Matt Joiner about 5 years"all network interfaces", I don't even have eth0 on my system
-
Marco over 4 yearsOP wants a method to gather this info using
/proc
, not actual cmds. -
F. Hauri - Give Up GitHub almost 3 yearsWhy ` <<< "$(</proc/...)"` instead of simply
awk '..' </proc/...
-
Torxed over 2 yearsOld as gold, but here's a slight modification to support netmasks and bump to Python3: github.com/Torxed/Scripts/blob/…