Open devansh08 opened 2 years ago
Hi, Thank you so much. I need to review Ubuntu daily for this. I'll come back. Best regards.
Hi,
As you can see, in Ubuntu 22.04 is working fine, even the help is right.
I'll leave the merge propose for the future, but I'll not merge right now.
Best regards and thank you so much for the help!
Glad to know it works well. Thanks for taking a look! Hope it makes it in the next releases :)
@costales I saw there is this library netifaces
(unfortunately it is now unmaintained but still works on Ubuntu 22.04) that can retrieve IP addresses on all platforms without using system commands at all.
In ufw_backend.py
I imported from netifaces import interfaces, ifaddresses, AF_INET
, and then edited get_net_ip
this way:
def get_net_ip(self):
return ' '.join([i['addr'] for ifaceName in interfaces() for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':None}]) if i['addr'] and not i['addr'].startswith('127.')])
By excluding loopback ips in subnet 127.0.0.0/8 (127.0.0.1 - 127.255.255.254) and interfaces that have no IP address we can reproduce hostname --all-ip-addresses
output without checking if we are on a specific system.
@devansh08 can you confirm this works in Arch Linux too?
@a13ssandr0 Yes this does work on Arch for me :) But I don't think ' '.join
should be done since systems having multiple network interfaces will return an array and this will give a space separated set of IPs. In my case it gave my WLAN interface IP and docker's default network interface IP. I think you can just use whatever is at the first index in the array.
Coming to the point of using netifaces
, not sure if it would be a good idea to use since it is unmaintained right now (but that's @costales decision to make).
Although based on your idea (great idea btw :+1: ) I found another way to get IP addresses using the socket
library (which is built-in for python3). This works for me on Arch, can you see if something like this works on Ubuntu for you ?
import socket
def get_net_ip(self):
return socket.gethostbyname(socket.getfqdn())
@a13ssandr0 Yes this does work on Arch for me :) But I don't think
' '.join
should be done since systems having multiple network interfaces will return an array and this will give a space separated set of IPs. In my case it gave my WLAN interface IP and docker's default network interface IP. I think you can just use whatever is at the first index in the array.
@devansh08 you're right, using ' '.join
isn't the right choice but I found that it perfectly reproduces hostname --all-ip-addresses
output (even though ufw only accepts one IP per rule, but this part could be a bit off-topic).
Here you can see my physical network interface has two IPs, while the third belongs to virsh
's virtual card.
#bash
$ hostname --all-ip-addresses
192.168.1.50 192.168.0.5 192.168.122.1
#python
>>> from netifaces import interfaces, ifaddresses, AF_INET
>>> ' '.join([i['addr'] for ifaceName in interfaces() for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':None}]) if i['addr'] and not i['addr'].startswith('127.')])
'192.168.1.50 192.168.0.5 192.168.122.1'
Although based on your idea (great idea btw +1 ) I found another way to get IP addresses using the
socket
library (which is built-in for python3). This works for me on Arch, can you see if something like this works on Ubuntu for you ?
Good idea using built-ins, but your code only returns '127.0.1.1'
(because it only relies on /etc/hosts
that gives that IP for my hostname) so I looked online and found this solution that also uses socket but tries to connect to the internet to get the actual IP used for routing:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80)) #you could also use `('<broadcast>', 0)` instead of Google DNS
print(s.getsockname()[0])
s.close()
Good idea using built-ins, but your code only returns '127.0.1.1' (because it only relies on /etc/hosts that gives that IP for my hostname) so I looked online and found this solution that also uses socket but tries to connect to the internet to get the actual IP used for routing:
Oh... My /etc/hosts
file currently only has 127.0.0.1 localhost
so for me it worked (not sure where exactly I have mapped my hostname arch
to my dynamic LAN IP). I also did find the code I shared in the same StackOverflow thread :) Didn't think the 8.8.8.8
solution would be great since it needs to be able to connect to external IPs which might not always be possible for a machine.
Another similar solution from the same thread:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(0)
s.connect(('10.255.255.255', 1))
ip = s.getsockname()[0]
Not sure if hitting 10.255.255.255
would be any issue on some kind of network setup, but otherwise looks fine to me. I don't think it should be a problem since it seems to be like just a ping to a local LAN IP on port 1. This should also not give 127.0.0.1
since the IP is still outside the machine.
@a13ssandr0 What do you think ? And does this work for your machine as well ?
Didn't think the
8.8.8.8
solution would be great since it needs to be able to connect to external IPs which might not always be possible for a machine. [ . . . ] Not sure if hitting10.255.255.255
would be any issue on some kind of network setup, but otherwise looks fine to me. I don't think it should be a problem since it seems to be like just a ping to a local LAN IP on port 1. This should also not give127.0.0.1
since the IP is still outside the machine.
@devansh08 any IP outside the machine is fine, even if it isn't reachable, because we only need to reach the local router, actual routing is not needed; 10.255.255.255
is the broadcast address of the a 10.x.x.x
local network so it's still fine.
@a13ssandr0 What do you think ? And does this work for your machine as well ? Yes, your code worked like a charm on first try :+1:
I noticed on clicking the "Paste your current local IP" the command
hostname --all-ip-addresses
is run. But with the GNU version of the hostname that I have pre installed on Arch Linux does not have this option. Instead it uses--ip-addresses
option. So I've added a check for valid IP addresses that the command returns (as for me the command returned an error message string) and some logic to try the GNU version's option before falling back to 127.0.0.1.Lemme know your thoughts. Thanks !
FYR, some info on the GNU version of hostname
``` hostname --help Usage: hostname [OPTION...] [NAME] Show or set the system's host name. -a, --aliases alias names -d, --domain DNS domain name -f, --fqdn, --long DNS host name or FQDN -F, --file=FILE set host name or NIS domain name from FILE -i, --ip-addresses addresses for the host name -s, --short short host name -y, --yp, --nis NIS/YP domain name -?, --help give this help list --usage give a short usage message -V, --version print program version Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options. Report bugs to