getmac
getmac copied to clipboard
Call to get_mac_address hangs when called with unknown IP-address
Describe the bug
If I call get_mac_address
and specify an IP-address for which the corresponding ARP entry doesn't exist on the system, the call will hang for a long time. It doesn't matter the value of network_request
.
To Reproduce
import logging
logging.basicConfig(level=logging.DEBUG)
import getmac
getmac.getmac.DEBUG = 1000 # Something high
getmac.get_mac_address(ip='10.0.0.1', network_request=False)
Yields this:
DEBUG:getmac:Trying: '_read_arp_file' (to_find: '10.0.0.1')
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: '<lambda>' (to_find: '10.0.0.1')
DEBUG:getmac:Running: '/bin/ip neighbor show 10.0.0.1'
DEBUG:getmac:Output from '/bin/ip' command: b''
DEBUG:getmac:Exception: list index out of range
DEBUG:getmac:Traceback (most recent call last):
File "/home/postlund/pyatv_dev/pyatv/lib/python3.6/site-packages/getmac/getmac.py", line 525, in _try_methods
found = m(to_find)
File "/home/postlund/pyatv_dev/pyatv/lib/python3.6/site-packages/getmac/getmac.py", line 485, in <lambda>
.partition(x)[2].partition('lladdr')[2].strip().split()[0],
IndexError: list index out of range
DEBUG:getmac:Trying: 'arp 10.0.0.1'
DEBUG:getmac:Running: '/usr/sbin/arp 10.0.0.1'
DEBUG:getmac:Output from '/usr/sbin/arp' command: b'10.0.0.1 (10.0.0.1) -- no entry\n'
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: 'arp -an'
DEBUG:getmac:Running: '/usr/sbin/arp -an'
DEBUG:getmac:Output from '/usr/sbin/arp' command: <<stripped>>
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: 'arp -an 10.0.0.1'
DEBUG:getmac:Running: '/usr/sbin/arp -an 10.0.0.1'
DEBUG:getmac:Output from '/usr/sbin/arp' command: b'arp: in 40 entries no match found.\n'
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: 'arp 10.0.0.1'
DEBUG:getmac:Running: '/usr/sbin/arp 10.0.0.1'
DEBUG:getmac:Output from '/usr/sbin/arp' command: b'10.0.0.1 (10.0.0.1) -- no entry\n'
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: 'arp -a'
DEBUG:getmac:Running: '/usr/sbin/arp -a'
<<HANGS HERE>>
The address resolution probably takes all the time. Since the same command has already been run (with expected -n
flag), the last call shouldn't even be needed.
Expected behavior Should return "fast".
System info (please complete the following information):
- OS name: Debian Linux
- OS Version: Some old version, like 7.1 maybe
- Python version: 3.6.1 x64
Additional context The command takes long time to execute if I run it manually from a shell as well.
Thank you for the detailed report!
Generally speaking, the case of a non-existent host is currently severely punished performance wise, due to hitting every command available. This is a known issue, and one that I'm currently in the progress of addressing, though a fix probably won't be out for a while (essentially, the core logic of how commands are checked and failures handled is being refactored completely). The redundant commands is a significant part of this issue, since currently it doesn't know for sure what command will work on what platform (e.g. differing syntax between versions of command included, distro-specific customization of output that appeared in X-release of the distro only, etc.). Once fixed, if it can't find the address in, say, the /proc/net/arp
, it'll fail without trying the other commands.
That notwithstanding, in this specific case it's quite odd that arp 10.0.0.1
is being run twice, and I can't tell from a cursory glance of the code why that would happen. If you get a chance, could you provide some more information?
- Version of
net-tools
:apt-cache show net-tools | grep "Version"
- Version of
getmac
:getmac --version
(orimport getmac;print(getmac.__version__);
) -
lsb_release -a
-
uname -a
One potential (though far from ideal) workaround is to execute the function in a thread and timeout after a short while, e.g. thread.join(timeout=0.5)
. Docs: https://docs.python.org/3.7/library/threading.html#threading.Thread.join
If you can think of a way to fix it in getmac
though I'm all ears, just short on time for the next few months.
Thanks for the fast reply! Yeah, I agree with you that all the redundant commands are a culprit here. I'm just gonna keep it short and say that these are the offending lines:
# Darwin oddness
(r'\(' + esc + r'\)\s+at\s+' + MAC_RE_DARWIN,
0, 'arp', [to_find, '-a', '-a %s' % to_find]),
I tried removing them at it worked after that (and since Debian is not Darwin, that seems reasonable too). I don't have my Mac in front of me, so I can't check what arp
accepts there (in case of a non-resolve flag). Maybe just include the Darwin-stuff in case of running on Darwin as a work-around?
Also, I would recommend hardcoding paths to commands to avoid potential PATH-hijacking:
https://www.hackingarticles.in/linux-privilege-escalation-using-path-variable/
It's a complete different issue, but i mention it so I don't forget.
That seems reasonable enough. Pretty busy currently, so while I may be able to get to it Saturday, it'll probably be more like next Saturday since I need to find the old Mac I used for testing. If you're able to test a fix on your Mac though I'd be fine with accepting that as well.
Thanks for the heads up on PATH, definitely agree it's a potential issue. I'll have to look into how to mitigate it without breaking compatibility.
I updated my findpi package to use this and I didn't want to have it hang, so I implemented this:
def ThreadId(ipaddress, macaddress):
macaddress = get_mac_address(ip=ipaddress)
if macaddress:
if ("b8:27:eb" in str(macaddress.lower())) or ("dc:a6:32" in str(macaddress.lower())):
print(f'Found pi: {ipaddress}')
def checkMacs(ip_address):
"""
checks if mac address found from nmap that matches raspberry pi
Accepts: ip_address var as string
Returns: nothing
Prints: found ip of pi if found
"""
macaddress = str()
th = threading.Thread(target=ThreadId, args=(ip_address, macaddress))
#data = get_mac_address(ip=ip_address)
th.start()
th.join(timeout=0.5)
return
based on the suggestion to use thread and setting a timeout. Seems to work fine and findpi continues to be faster than nmap to find pi's on a network. Thanks!
Using getmac version 0.8.3 on:
$ uname -a
Linux hosanna 5.18.10-76051810-generic #202207071639~1659403207~20.04~cb5f582~dev-Ubuntu SMP PREEMPT_DY x86_64 x86_64 x86_64 GNU/Linux
$ lsb_release -a
LSB Version: core-11.1.0ubuntu2-noarch:printing-11.1.0ubuntu2-noarch:security-11.1.0ubuntu2-noarch
Distributor ID: Ubuntu
Description: Ubuntu 20.04.5 LTS
Release: 20.04
Codename: focal
I do not get this hang. Debug output:
>>> getmac.get_mac_address(ip='10.0.0.1', network_request=False)
DEBUG:getmac:Trying: '_read_arp_file' (to_find: '10.0.0.1')
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: '<lambda>' (to_find: '10.0.0.1')
DEBUG:getmac:Running: '/sbin/ip neighbor show 10.0.0.1'
DEBUG:getmac:Output from '/sbin/ip' command: b''
DEBUG:getmac:Exception: list index out of range
DEBUG:getmac:Traceback (most recent call last):
File "/home/jkugler/.local/lib/python3.8/site-packages/getmac/getmac.py", line 590, in _try_methods
found = m(to_find)
File "/home/jkugler/.local/lib/python3.8/site-packages/getmac/getmac.py", line 537, in <lambda>
lambda x: _popen("ip", "neighbor show %s" % x)
IndexError: list index out of range
DEBUG:getmac:Trying: 'arp 10.0.0.1'
DEBUG:getmac:Running: '/usr/sbin/arp 10.0.0.1'
DEBUG:getmac:Output from '/usr/sbin/arp' command: b'10.0.0.1 (10.0.0.1) -- no entry\n'
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: 'arp -an'
DEBUG:getmac:Running: '/usr/sbin/arp -an'
DEBUG:getmac:Output from '/usr/sbin/arp' command: b'? (192.168.1.2) at c0:56:27:d2:b0:98 [ether] on wlp4s0\n? (192.168.1.187) at
f8:0f:f9:88:2c:2e [ether] on wlp4s0\n? (192.168.1.164) at c8:e0:eb:38:31:2b [ether] on wlp4s0\n? (192.168.122.70) at <incomplet
e> on virbr0\n? (192.168.1.185) at 84:ea:ed:90:0a:5f [ether] on wlp4s0\n? (192.168.1.1) at 98:5d:ad:d8:6d:8a [ether] on wlp4s0\n
'
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: 'arp -an 10.0.0.1'
DEBUG:getmac:Running: '/usr/sbin/arp -an 10.0.0.1'
DEBUG:getmac:Output from '/usr/sbin/arp' command: b'arp: in 6 entries no match found.\n'
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: 'arp 10.0.0.1'
DEBUG:getmac:Running: '/usr/sbin/arp 10.0.0.1'
DEBUG:getmac:Output from '/usr/sbin/arp' command: b'10.0.0.1 (10.0.0.1) -- no entry\n'
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: 'arp -a'
DEBUG:getmac:Running: '/usr/sbin/arp -a'
DEBUG:getmac:Output from '/usr/sbin/arp' command: b'? (192.168.1.2) at c0:56:27:d2:b0:98 [ether] on wlp4s0\nGoogle-Nest-Mini.aza
riah.com (192.168.1.187) at f8:0f:f9:88:2c:2e [ether] on wlp4s0\nariel.azariah.com (192.168.1.164) at c8:e0:eb:38:31:2b [ether]
on wlp4s0\n? (192.168.122.70) at <incomplete> on virbr0\nRokuUltra.azariah.com (192.168.1.185) at 84:ea:ed:90:0a:5f [ether] on w
lp4s0\ngateway (192.168.1.1) at 98:5d:ad:d8:6d:8a [ether] on wlp4s0\n'
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: 'arp -a 10.0.0.1'
DEBUG:getmac:Running: '/usr/sbin/arp -a 10.0.0.1'
DEBUG:getmac:Output from '/usr/sbin/arp' command: b'arp: in 6 entries no match found.\n'
DEBUG:getmac:Result: None
DEBUG:getmac:Trying: '_uuid_ip' (to_find: '10.0.0.1')
DEBUG:getmac:Result: None
DEBUG:getmac:Raw MAC found: None
This should be resolved with version 0.9.0. If it's still occurring, please re-open the issue, and include log output of the issue using the 0.9.0 release.